工具:

 <dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>

定义接口

 package com.snow.tailer;

 public interface TailerListener {
/**
* The tailer will call this method during construction,
* giving the listener a method of stopping the tailer.
* @param tailer the tailer.
*/
void init(Tailer tailer); /**
* This method is called if the tailed file is not found.
* <p>
* <b>Note:</b> this is called from the tailer thread.
*/
void fileNotFound(); /**
* Called if a file rotation is detected.
*
* This method is called before the file is reopened, and fileNotFound may
* be called if the new file has not yet been created.
* <p>
* <b>Note:</b> this is called from the tailer thread.
*/
void fileRotated(); /**
* Handles a line from a Tailer.
* <p>
* <b>Note:</b> this is called from the tailer thread.
* @param line the line.
*/
void handle(String line); /**
* Handles an Exception .
* <p>
* <b>Note:</b> this is called from the tailer thread.
* @param ex the exception.
*/
void handle(Exception ex);
}

接口实现

 package com.snow.tailer;

 public class TailerListenerAdapter implements TailerListener {
/**
* The tailer will call this method during construction,
* giving the listener a method of stopping the tailer.
* @param tailer the tailer.
*/
public void init(Tailer tailer) {
} /**
* This method is called if the tailed file is not found.
*/
public void fileNotFound() {
} /**
* Called if a file rotation is detected.
*
* This method is called before the file is reopened, and fileNotFound may
* be called if the new file has not yet been created.
*/
public void fileRotated() {
} /**
* Handles a line from a Tailer.
* @param line the line.
*/
public void handle(String line) {
} /**
* Handles an Exception .
* @param ex the exception.
*/
public void handle(Exception ex) {
} }

定义Tailer.java

 /*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.snow.tailer; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile; /**
* Simple implementation of the unix "tail -f" functionality.
* <p>
* <h2>1. Create a TailerListener implementation</h3>
* <p>
* First you need to create a {@link TailerListener} implementation
* ({@link TailerListenerAdapter} is provided for convenience so that you don't have to
* implement every method).
* </p>
*
* <p>For example:</p>
* <pre>
* public class MyTailerListener extends TailerListenerAdapter {
* public void handle(String line) {
* System.out.println(line);
* }
* }
* </pre>
*
* <h2>2. Using a Tailer</h2>
*
* You can create and use a Tailer in one of three ways:
* <ul>
* <li>Using one of the static helper methods:
* <ul>
* <li>{@link Tailer#create(File, TailerListener)}</li>
* <li>{@link Tailer#create(File, TailerListener, long)}</li>
* <li>{@link Tailer#create(File, TailerListener, long, boolean)}</li>
* </ul>
* </li>
* <li>Using an {@link java.util.concurrent.Executor}</li>
* <li>Using an {@link Thread}</li>
* </ul>
*
* An example of each of these is shown below.
*
* <h3>2.1 Using the static helper method</h3>
*
* <pre>
* TailerListener listener = new MyTailerListener();
* Tailer tailer = Tailer.create(file, listener, delay);
* </pre>
*
* <h3>2.2 Use an Executor</h3>
*
* <pre>
* TailerListener listener = new MyTailerListener();
* Tailer tailer = new Tailer(file, listener, delay);
*
* // stupid executor impl. for demo purposes
* Executor executor = new Executor() {
* public void execute(Runnable command) {
* command.run();
* }
* };
*
* executor.execute(tailer);
* </pre>
*
*
* <h3>2.3 Use a Thread</h3>
* <pre>
* TailerListener listener = new MyTailerListener();
* Tailer tailer = new Tailer(file, listener, delay);
* Thread thread = new Thread(tailer);
* thread.setDaemon(true); // optional
* thread.start();
* </pre>
*
* <h2>3. Stop Tailing</h3>
* <p>Remember to stop the tailer when you have done with it:</p>
* <pre>
* tailer.stop();
* </pre>
*
* @see TailerListener
* @see TailerListenerAdapter
* @version $Id: Tailer.java 1348698 2012-06-11 01:09:58Z ggregory $
* @since 2.0
*/
public class Tailer implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(Tailer.class); private static final int DEFAULT_DELAY_MILLIS = 1000; private static final String RAF_MODE = "r"; private static final int DEFAULT_BUFSIZE = 4096; /**
* Buffer on top of RandomAccessFile.
*/
private final byte inbuf[]; /**
* The file which will be tailed.
*/
private final File file; /**
* The amount of time to wait for the file to be updated.
*/
private final long delayMillis; /**
* Whether to tail from the end or start of file
*/
private final boolean end; /**
* The listener to notify of events when tailing.
*/
private final TailerListener listener; /**
* Whether to close and reopen the file whilst waiting for more input.
*/
private final boolean reOpen; /**
* The tailer will run as long as this value is true.
*/
private volatile boolean run = true;
private volatile boolean resetFilePositionIfOverwrittenWithTheSameLength = false; /**
* Creates a Tailer for the given file, starting from the beginning, with the default delay of 1.0s.
* @param file The file to follow.
* @param listener the TailerListener to use.
*/
public Tailer(File file, TailerListener listener) {
this(file, listener, DEFAULT_DELAY_MILLIS);
} /**
* Creates a Tailer for the given file, starting from the beginning.
* @param file the file to follow.
* @param listener the TailerListener to use.
* @param delayMillis the delay between checks of the file for new content in milliseconds.
*/
public Tailer(File file, TailerListener listener, long delayMillis) {
this(file, listener, delayMillis, false);
} /**
* Creates a Tailer for the given file, with a delay other than the default 1.0s.
* @param file the file to follow.
* @param listener the TailerListener to use.
* @param delayMillis the delay between checks of the file for new content in milliseconds.
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
*/
public Tailer(File file, TailerListener listener, long delayMillis, boolean end) {
this(file, listener, delayMillis, end, DEFAULT_BUFSIZE);
logger.info("Tailer inited from customer class.");
} /**
* Creates a Tailer for the given file, with a delay other than the default 1.0s.
* @param file the file to follow.
* @param listener the TailerListener to use.
* @param delayMillis the delay between checks of the file for new content in milliseconds.
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
* @param reOpen if true, close and reopen the file between reading chunks
*/
public Tailer(File file, TailerListener listener, long delayMillis, boolean end, boolean reOpen) {
this(file, listener, delayMillis, end, reOpen, DEFAULT_BUFSIZE);
} /**
* Creates a Tailer for the given file, with a specified buffer size.
* @param file the file to follow.
* @param listener the TailerListener to use.
* @param delayMillis the delay between checks of the file for new content in milliseconds.
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
* @param bufSize Buffer size
*/
public Tailer(File file, TailerListener listener, long delayMillis, boolean end, int bufSize) {
this(file, listener, delayMillis, end, false, bufSize);
} /**
* Creates a Tailer for the given file, with a specified buffer size.
* @param file the file to follow.
* @param listener the TailerListener to use.
* @param delayMillis the delay between checks of the file for new content in milliseconds.
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
* @param reOpen if true, close and reopen the file between reading chunks
* @param bufSize Buffer size
*/
public Tailer(File file, TailerListener listener, long delayMillis, boolean end, boolean reOpen, int bufSize) {
this.file = file;
this.delayMillis = delayMillis;
this.end = end; this.inbuf = new byte[bufSize]; // Save and prepare the listener
this.listener = listener;
listener.init(this);
this.reOpen = reOpen;
} /**
* Creates and starts a Tailer for the given file.
*
* @param file the file to follow.
* @param listener the TailerListener to use.
* @param delayMillis the delay between checks of the file for new content in milliseconds.
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
* @param bufSize buffer size.
* @return The new tailer
*/
public static Tailer create(File file, TailerListener listener, long delayMillis, boolean end, int bufSize) {
Tailer tailer = new Tailer(file, listener, delayMillis, end, bufSize);
Thread thread = new Thread(tailer);
thread.setDaemon(true);
thread.start();
return tailer;
} /**
* Creates and starts a Tailer for the given file.
*
* @param file the file to follow.
* @param listener the TailerListener to use.
* @param delayMillis the delay between checks of the file for new content in milliseconds.
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
* @param reOpen whether to close/reopen the file between chunks
* @param bufSize buffer size.
* @return The new tailer
*/
public static Tailer create(File file, TailerListener listener, long delayMillis, boolean end, boolean reOpen, int bufSize) {
Tailer tailer = new Tailer(file, listener, delayMillis, end, reOpen, bufSize);
Thread thread = new Thread(tailer);
thread.setDaemon(true);
thread.start();
return tailer;
} /**
* Creates and starts a Tailer for the given file with default buffer size.
*
* @param file the file to follow.
* @param listener the TailerListener to use.
* @param delayMillis the delay between checks of the file for new content in milliseconds.
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
* @return The new tailer
*/
public static Tailer create(File file, TailerListener listener, long delayMillis, boolean end) {
return create(file, listener, delayMillis, end, DEFAULT_BUFSIZE);
} /**
* Creates and starts a Tailer for the given file with default buffer size.
*
* @param file the file to follow.
* @param listener the TailerListener to use.
* @param delayMillis the delay between checks of the file for new content in milliseconds.
* @param end Set to true to tail from the end of the file, false to tail from the beginning of the file.
* @param reOpen whether to close/reopen the file between chunks
* @return The new tailer
*/
public static Tailer create(File file, TailerListener listener, long delayMillis, boolean end, boolean reOpen) {
return create(file, listener, delayMillis, end, reOpen, DEFAULT_BUFSIZE);
} /**
* Creates and starts a Tailer for the given file, starting at the beginning of the file
*
* @param file the file to follow.
* @param listener the TailerListener to use.
* @param delayMillis the delay between checks of the file for new content in milliseconds.
* @return The new tailer
*/
public static Tailer create(File file, TailerListener listener, long delayMillis) {
return create(file, listener, delayMillis, false);
} /**
* Creates and starts a Tailer for the given file, starting at the beginning of the file
* with the default delay of 1.0s
*
* @param file the file to follow.
* @param listener the TailerListener to use.
* @return The new tailer
*/
public static Tailer create(File file, TailerListener listener) {
return create(file, listener, DEFAULT_DELAY_MILLIS, false);
} /**
* Return the file.
*
* @return the file
*/
public File getFile() {
return file;
} /**
* Return the delay in milliseconds.
*
* @return the delay in milliseconds.
*/
public long getDelay() {
return delayMillis;
} /**
* Follows changes in the file, calling the TailerListener's handle method for each new line.
*/
@Override
public void run() {
RandomAccessFile reader = null;
try {
long last = 0; // The last time the file was checked for changes
long position = 0; // position within the file
// Open the file
while (run && reader == null) {
try {
reader = new RandomAccessFile(file, RAF_MODE);
} catch (FileNotFoundException e) {
listener.fileNotFound();
} if (reader == null) {
try {
Thread.sleep(delayMillis);
} catch (InterruptedException e) {
}
} else {
// The current position in the file
position = end ? file.length() : 0;
last = file.lastModified();
reader.seek(position);
}
} while (run) { boolean newer = FileUtils.isFileNewer(file, last); // IO-279, must be done first // Check the file length to see if it was rotated
long length = file.length(); if (length < position) {
logger.info(String.format("rotated, legth=%s, position=%s", length, position));
// File was rotated
listener.fileRotated(); // Reopen the reader after rotation
try {
// Ensure that the old file is closed iff we re-open it successfully
RandomAccessFile save = reader;
reader = new RandomAccessFile(file, RAF_MODE);
position = 0;
// close old file explicitly rather than relying on GC picking up previous
// RAF
IOUtils.closeQuietly(save);
} catch (FileNotFoundException e) {
// in this case we continue to use the previous reader and position values
listener.fileNotFound();
}
continue;
} else { // File was not rotated // See if the file needs to be read again
if (length > position) { // The file has more content than it did last time
position = readLines(reader);
last = file.lastModified(); } else if (newer) {
logger.info(String.format("newer, legth=%s, position=%s", length, position));
if (resetFilePositionIfOverwrittenWithTheSameLength) {
/*
* This can happen if the file is truncated or overwritten with the exact same length of
* information. In cases like this, the file position needs to be reset
*/
position = 0;
reader.seek(position); // cannot be null here // Now we can read new lines
position = readLines(reader);
}
last = file.lastModified();
}
}
if (reOpen) {
IOUtils.closeQuietly(reader);
}
try {
Thread.sleep(delayMillis);
} catch (InterruptedException e) {
}
if (run && reOpen) {
reader = new RandomAccessFile(file, RAF_MODE);
reader.seek(position);
logger.info(String.format("reopen, legth=%s, position=%s", length, position));
}
} } catch (Exception e) { listener.handle(e); } finally {
IOUtils.closeQuietly(reader);
}
} /**
* Allows the tailer to complete its current loop and return.
*/
public void stop() {
this.run = false;
} /**
* Read new lines.
*
* @param reader The file to read
* @return The new position after the lines have been read
* @throws IOException if an I/O error occurs.
*/
private long readLines(RandomAccessFile reader) throws IOException {
StringBuilder sb = new StringBuilder(); long pos = reader.getFilePointer();
long rePos = pos; // position to re-read int num;
boolean seenCR = false;
while (run && ((num = reader.read(inbuf)) != -1)) {
for (int i = 0; i < num; i++) {
byte ch = inbuf[i];
switch (ch) {
case '\n':
seenCR = false; // swallow CR before LF
listener.handle(sb.toString());
sb.setLength(0);
rePos = pos + i + 1;
break;
case '\r':
if (seenCR) {
sb.append('\r');
}
seenCR = true;
break;
default:
if (seenCR) {
seenCR = false; // swallow final CR
listener.handle(sb.toString());
sb.setLength(0);
rePos = pos + i + 1;
}
sb.append((char) ch); // add character, not its ascii value
}
} pos = reader.getFilePointer();
} reader.seek(rePos); // Ensure we can re-read if necessary
return rePos;
} }

封装使用函数:

 /**
* @param inputFile 监控文件
* @param sleepInterval 当文件没有日志时sleep间隔
*/
private static void monitor(String inputFile, int sleepInterval) {
TailerListener listener = new TailerListenerAdapter() {
@Override
public void handle(String line) {
if (++count % 100000 == 0) {
log.info("{} lines sent since the program up.", count);
}
if (StringUtils.isEmpty(line)) {
log.warn("should not read empty line.");
return;
} else {
// do something ...
}
}
};
Tailer tailer = new Tailer(new File(inputFile), listener, sleepInterval, true);
tailer.run();
}

调用该函数即可。

JAVA 实现tail -f 日志文件监控功能的更多相关文章

  1. Linux下日志文件监控系统Logwatch的使用记录

    Linux下日志文件监控系统Logwatch的使用记录 原文:http://www.cnblogs.com/kevingrace/p/6519504.html 在维护Linux服务器时,经常需要查看系 ...

  2. C#使用FileSystemWatcher控件实现的文件监控功能示例

    本文实例讲述了C#使用FileSystemWatcher控件实现的文件监控功能.分享给大家供大家参考,具体如下: FileSystemWatcher 可以使用FileSystemWatcher组件监视 ...

  3. 四步搞定Zabbix 日志文件监控

    Zabbix 日志文件监控 一.给运行Zabbix agent的用户授予要监控日志的读取权限. 1. 執行下面的命令,追加app的可讀權限: setfacl -m u:app:r-- /var/log ...

  4. tail -f 实时查看日志文件 linux查看日志后100行

    tail -f 实时查看日志文件 tail -f 日志文件logtail - 100f 实时查看日志文件 后一百行tail -f -n 100 catalina.out linux查看日志后100行搜 ...

  5. 使用tail命令实时查看日志文件

    [Shell] 纯文本查看 复制代码 ? 1 tail -f /日志文件 好了.就这样用.简单吧    退出ctrl+C

  6. Linux 系统中如何查看日志 (常用命令) tail -f

    Linux 系统中如何查看日志 (常用命令)  tail -f 日志文件 日 志 文 件 说 明 /var/log/message 系统启动后的信息和错误日志,是Red Hat Linux中最常用的日 ...

  7. java实现文件监控

    文件监控器: package testfile; import org.apache.commons.io.monitor.FileAlterationListenerAdaptor; import ...

  8. 关于linux的一点好奇心(四):tail -f文件跟踪实现

    关于文件跟踪,我们有很多的实际场景,比如查看某个系统日志的输出,当有变化时立即体现,以便进行问题排查:比如查看文件结尾的内容是啥,总之是刚需了. 1. 自己实现的文件跟踪 我们平时做功能开发时,也会遇 ...

  9. tail -f 在对文件进行动态追踪时失效的问题

    在我是用 tail -f file.txt 对这个文件进行动态追踪时: 我重新打开一个新的终端进行vim编辑这个文件并且保存 这是我们发现,tail -f file.txt'动态追踪的这个文件没有任何 ...

随机推荐

  1. 《Metasploit魔鬼训练营》第四章(上)

    p128 wmap 和昨天一样,我用这些漏洞扫描工具去扫testfire.net或者owaspbwa都扫不出漏洞!不明白! 补充:原来是网络不知道啥时候自己断了.连上后再次扫描就成功了:

  2. LKD: Chapter 6 Kernel Data Structures

    这一章我们研究四种主要的数据结构: linked lists, queues, maps, binary trees. Linked Lists:(<linux/list.h>) 在lin ...

  3. python3学习笔记(2)

    一.面向对象(初识)由类和方法组成,类里面封装了很多功能,根据这个类,可以创建一个这个类的对象,即对象是根据这个类创建的,以后这个对象要使用某个功能的时候就从这个类里面的找.例:str -功能一 -功 ...

  4. linux基础命令整理(一)

    ls 显示当前目录内容 1)ls / (显示根目录下所有的目录和文件) 2)ls -l / (以列表的形式显示根目录下所有的目录和文件) 绝对路径和相对路径 1)绝对路径,以/开头的都是绝对路径,比如 ...

  5. webpack 3.X学习之JS压缩与打包HTML文件

    js压缩 webpack自带一个插件uglifyjs-webpack-plugin来压缩js,所以不需要再次安装,当一切都准备妥当,引入uglifyjs-webpack-plugin模块: const ...

  6. ExceptionLess 本地部署小结

    ExceptionLess 是一个免费开源分布式系统日志收集框架,地址:https://github.com/exceptionless/Exceptionless 运行环境: .NET 4.6.1 ...

  7. Java数据结构和算法(四)——栈

    前面我们讲解了数组,数组更多的是用来进行数据的存储,纯粹用来存储数据的数据结构,我们期望的是插入.删除和查找性能都比较好.对于无序数组,插入快,但是删除和查找都很慢,为了解决这些问题,后面我们会讲解比 ...

  8. 电子笔记本的思考(1)(ver0.3)

    章节:电子笔记本的思考(1)   陶哲轩在<解题·成长·快乐——陶哲轩教你学数学>中着重强调,用纸笔来“缓存”思维对于数学解题的重要性: 用选定的符号表达你所知道的信息,并画一个示意图.把 ...

  9. PHP获取路径或目录实现

    <?php /**  * PHP获取路径或目录实现  */    //魔术变量,获取当前文件的绝对路径 echo "__FILE__: ========> ".__FI ...

  10. 匈牙利标记法定义ECMAScript变量前缀

    匈牙利标记法定义ECMAScript变量前缀 类型 前缀 示例 数组 a aArray 布尔型 b bMale 浮点型(数字)   f fTax 函数 fn fnSwap 整型(数字) i iAge ...