原文链接:http://www.sjsjw.com/kf_cloud/article/020376ABA013802.asp

目的

实时监听某目录下的日志文件,如有新文件切换到新文件,并同步写入kafka,同时记录日志文件的行位置,以应对进程异常退出,能从上次的文件位置开始读取(考虑到效率,这里是每100条记一次,可调整)

源码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.net.NoRouteToHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig; /*
* 自己在源服务器写生产者往kafka插入数据,注意文件"producer.properties放在linux下该jar文件同一目录
* 监听某个目录下的文件数据然后写入kafka
* nohup java -jar portallog_producer.jar portallog /var/apache/logs portallog.position >/home/sre/portalhandler/handler.log 2>&1 &
*
*
*/
public class PortalLogTail_Line { private Producer<String,String> inner;
java.util.Random ran = new Random();
public PortalLogTail_Line() throws FileNotFoundException, IOException {
Properties properties = new Properties();
// properties.load(ClassLoader.getSystemResourceAsStream("producer.properties")); properties.load(new FileInputStream("producer.properties")); ProducerConfig config = new ProducerConfig(properties); inner = new Producer<String, String>(config); } public void send(String topicName,String message) {
if(topicName == null || message == null){
return;
}
// KeyedMessage<String, String> km = new KeyedMessage<String, String>(topicName,message);
//随机作为key,hash分散到各个分区
KeyedMessage<String, String> km = new KeyedMessage<String, String>(topicName,String.valueOf(ran.nextInt(9)),message);
// KeyedMessage<String, String> km = new KeyedMessage<String, String>(topicName,message,message);
inner.send(km); } public void send(String topicName,Collection<String> messages) {
if(topicName == null || messages == null){
return;
}
if(messages.isEmpty()){
return;
}
List<KeyedMessage<String, String>> kms = new ArrayList<KeyedMessage<String, String>>();
for(String entry : messages){
KeyedMessage<String, String> km = new KeyedMessage<String, String>(topicName,entry);
kms.add(km);
}
inner.send(kms);
} public void close(){
inner.close();
} public String getNewFile(File file)
{
File[] fs=file.listFiles();
long maxtime=0;
String newfilename="";
for (int i=0;i<fs.length;i++)
{
if (fs[i].lastModified()>maxtime && fs[i].getName().contains("access"))
{
maxtime=fs[i].lastModified();
newfilename=fs[i].getAbsolutePath(); }
}
return newfilename;
}
//写入文件名及行号
public void writePosition(String path,int rn,String positionpath)
{
try {
BufferedWriter out = new BufferedWriter(new FileWriter(positionpath));
out.write(path+","+rn);
out.close();
} catch (IOException e) {
}
}
LineNumberReader randomFile=null;
String newfile=null;
String thisfile=null;
String prefile=null;
int ln=0;
int beginln=0;
public void realtimeShowLog(final File file,final String topicname, final String positionpath) throws IOException{ //启动一个线程每1秒钟读取新增的日志信息
new Thread(new Runnable(){
public void run() {
thisfile=getNewFile(file);
prefile=thisfile;
//访问position文件,如果记录了文件路径,及行号,则定位,否则使用最新的文件
try {
BufferedReader br=new BufferedReader(new FileReader(positionpath));
String line=br.readLine();
if (line!=null &&line.contains(","))
{
thisfile=line.split(",")[0];
prefile=thisfile;
beginln=Integer.parseInt(line.split(",")[1]);
} } catch (FileNotFoundException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} //指定文件可读可写
try {
randomFile = new LineNumberReader(new FileReader(thisfile));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (true)
{
try {
Thread.sleep(100); } catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
//获得变化部分的
// randomFile.seek(lastTimeFileSize);
String tmp = "";
while( (tmp = randomFile.readLine())!= null) {
int currln=randomFile.getLineNumber();
//beginln默认为0
if (currln>beginln)
send(topicname,new String(tmp.getBytes("utf8"))); ln++; //每发生一条写一次影响效率,连续发100次后再记录位置
if (ln>100)
{
writePosition(thisfile,currln,positionpath);
ln=0;
} }
thisfile=getNewFile(file);
if(!thisfile.equals(prefile)) {
randomFile.close();
randomFile = new LineNumberReader(new FileReader(thisfile));
prefile=thisfile;
beginln=0;
} } catch (IOException e) {
throw new RuntimeException(e);
}
}
}}).start();
} /**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
PortalLogTail_Line producer = new PortalLogTail_Line();
if (args.length!=3)
{
System.out.println("usage:topicname pathname positionpath");
System.exit(1);
}
String topicname=args[0];
String pathname=args[1];
String positionpath=args[2];
final File tmpLogFile = new File(pathname);
producer.realtimeShowLog(tmpLogFile,topicname,positionpath); } }
producer.properties文件放在同级目录下

metadata.broker.list=xxx:10909,xxx:10909

# name of the partitioner class for partitioning events; default partition spreads data randomly
#partitioner.class= # specifies whether the messages are sent asynchronously (async) or synchronously (sync)
producer.type=sync
#producer.type=async # specify the compression codec for all data generated: none , gzip, snappy.
# the old config values work as well: 0, 1, 2 for none, gzip, snappy, respectivally
compression.codec=none
#compression.codec=gzip # message encoder
serializer.class=kafka.serializer.StringEncoder

测试

最后执行:

 nohup java -jar portallog_producer.jar portallog /var/apache/logs portallog.position  >/home/sre/portalhandler/handler.log 2>&1 &

java实时监听日志写入kafka(转)的更多相关文章

  1. java实时监听日志写入kafka(多目录)

    目的 实时监听多个目录下的日志文件,如有新文件切换到新文件,并同步写入kafka,同时记录日志文件的行位置,以应对进程异常退出,能从上次的文件位置开始读取(考虑到效率,这里是每100条记一次,可调整) ...

  2. java实时监听日志写入kafka

    目的 实时监听某目录下的日志文件,如有新文件切换到新文件,并同步写入kafka,同时记录日志文件的行位置,以应对进程异常退出,能从上次的文件位置开始读取(考虑到效率,这里是每100条记一次,可调整) ...

  3. 20180530利用Maxwell组件实时监听Mysql的binlog日志

    转自:https://blog.csdn.net/qq_30921461/article/details/78320750 http://kafka.apache.org/quickstart htt ...

  4. js 实时监听input中值变化

    注意:用到了jquery需要引入jquery.min.js. 需求: 1.每个地方需要分别打分,总分为100; 2.第一个打分总分为40; 3.第二个打分总分为60. 注意:需要判断null.&quo ...

  5. ORACLE清理、截断监听日志文件(listener.log)

    在ORACLE数据库中,如果不对监听日志文件(listener.log)进行截断,那么监听日志文件(listener.log)会变得越来越大,想必不少人听说过关于"LISTENER.LOG日 ...

  6. Java线程监听,意外退出线程后自动重启

    Java线程监听,意外退出线程后自动重启 某日,天朗气清,回公司,未到9点,刷微博,顿觉问题泛滥,惊恐万分! 前一天写了一个微博爬行程序,主要工作原理就是每隔2分钟爬行一次微博,获取某N个关注朋友微博 ...

  7. Android实时监听网络状态

    Android实时监听网络状态(1)   其实手机在网络方面的的监听也比较重要,有时候我们必须实时监控这个程序的实时网络状态,android在网络断开与连接的时候都会发出广播,我们通过接收系统的广播就 ...

  8. Oracle数据库运维:要对监听日志文件(listener.log)进行定期清理,如果不定期清理,会遇到下面一些麻烦

    原文链接: http://www.lookdaima.com/WebForms/WebPages/Blanks/Pm/Docs/DocItemDetail.aspx?EmPreviewTypeV=2& ...

  9. 移动端用js与jquery实时监听输入框值的改动

    背景: 在一次移动端H5开发中,需要监听输入框值的实时变动. onchange事件肯定抛弃,因为只能失去焦点才触发. 而keyPress在Android可以触发,iOS不可以. 又不想用Android ...

随机推荐

  1. sorted()排序详解

    sorted()排序详解     http://wiki.python.org/moin/HowTo/Sorting?highlight=%28howto%29#The_Old_Way_Using_t ...

  2. JAVAEE——宜立方商城13:Mycat数据库分片、主从复制、读写分离、100%Linux中成功安装Mysql的方法

    1 海量数据的存储问题 如今随着互联网的发展,数据的量级也是撑指数的增长,从GB到TB到PB.对数据的各种操作也是愈加的困难,传统的关系性数据库已经无法满足快速查询与插入数据的需求.这个时候NoSQL ...

  3. 初识thinkphp(3)

    这篇内容主要涉及请求相应内容. 该系列主要是个人笔记,且内容是连贯的,其中涉及到的自己写的模块或者方法在前面文章中有介绍咋来的,如果您看得云里雾里,给您带来不便,真的不好意思. 0x01:请求对象 官 ...

  4. 循序渐进学.Net Core Web Api开发系列【11】:依赖注入

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.概述 本篇介绍如 ...

  5. [代码审计]eyoucms前台未授权任意文件上传

    0x00 背景 来公司差不多一年了,然而我却依旧没有转正.约莫着转正也要到九月了,去年九月来的,实习,转正用了一年.2333 废话不多说了,最近有其他的事要忙,很久没有代码审计了.难的挖不了,浅的没意 ...

  6. Uncaught Error: Syntax error, unrecognized expression: [flag=]报错处理方法

    今早运行项目的时候报这个错误: 百度翻译的解释是:未命名错误:语法错误,未识别表达式:[FLAG= ]   也就是书写规范问题. 可是我查了对应的js: 字符串拼接没什么问题,经常这样写. 这时看报错 ...

  7. Django Model._meta API

    Model._meta API是Django ORM的核心,它使得lookups.queries.forms.admin这些模块通过每个model类的_meta的属性可以了解每个model的情况. 1 ...

  8. BZOJ.4355.Play with sequence(线段树)

    题目链接 问题在于操作二.操作二可以拆分成:区间加\(C\).区间(对\(0\))取\(\max\). 注意到操作一的\(C\)都是非负数,即数列中不会出现负数,所以我们直接维护最小值和最小值出现的次 ...

  9. CS1.6找金钱和人物血量

    一.查找金钱数量 先搜索800 然后购买东西,再搜索剩下的钱 然后发现有两个地址,一个绿色的地址(也就是静态地址),还有一个动态地址 经过测试后,静态地址的值是对应屏幕上的值,而真正实际的金钱是那个动 ...

  10. [洛谷1681]最大正方形II

    思路:对于矩阵中的每一个元素,处理出它能扩展到的上边界$up$.左边界$left$,DP得出以该元素为右下角的最大正方形.状态转移方程:$f_{i,j}=min(f_{i-1,j-1},up_{i,j ...