ELK日志服务

1.环境准备

操作系统:CentOS7(虚拟机上跑)

Java版本:JDK1.7(只需要JVM,可以只安装jre)

ELK:ElasticSearch: 2.1.0,

Logstash: 2.1.1,

Kibana: 4.3.0 参考:

https://www.kancloud.cn/hanxt/elk/216151,

https://my.oschina.net/itblog/blog/547250

2.安装ElasticSearch

elasticsearch中文教程:http://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/《elasticsearch权威指南》

去官网下载压缩包,解压在CentOS7的  /home/lin/elk/elasticsearch-2.1.0/ 下

bin:可执行文件 config:配置文件

data:es放数据的文件夹

lib:运行时库

logs:日志文件

plugins:插件文件

进入到 elasticsearch 的解压目录下,安装head插件:

./bin/plugin install mobz/elasticsearch-head

如果权限不够要赋予权限。安装完head插件后进入plugins目录下看是否有一个head目录:ls plugins/

然后编辑 elasticsearch 的配置文件:

vi config/elasticsearch.yml

只需要修改下面几个参数:

cluster.name: es_cluster node.name: node0

#如果没有这个目录要新建一个 path.data: /home/lin/elk/elasticsearch-2.1.0/data

#如果没有这个目录要新建一个 path.logs: /home/lin/elk/elasticsearch-2.1.0/logs #当前hostname或IP,这里是虚拟机的IP地址 network.host=192.168.112.128

#接受http请求的端口 network.port=9200

保存修改的配置文件退出后运行elasticsearch:

./bin/elasticsearch

注意,在linux系统下不能以root用户权限运行elasticsearch,并且jdk版本至少要1.7,否则报错。

成功运行后如下:

其中9300是elasticsearch与其他节点传输的端口,9200是elasticsearch接受http请求的端口。

然后在外部机器上的浏览器访问:http://192.168.112.128:9200/ 在浏览器看到如下json串信息:

或者也可以使用curl命令 curl 'http://192.168.112.128:9200/?pretty' 来看是否成功启动,成功启动终端会打印一个json:

{

"name" : "node0",

"cluster_name" : "es_cluster",

"version" : {

"number" : "2.1.0",

"build_hash" : "72cd1f1a3eee09505e036106146dc1949dc5dc87",

"build_timestamp" : "2015-11-18T22:40:03Z",

"build_snapshot" : false,

"lucene_version" : "5.3.1"

},

"tagline" : "You Know, for Search"

}

如果无法访问,很可能需要检查虚拟机是否设置了防火墙,把9200端口开启一下:

/sbin/iptables -I INPUT -p tcp --dport 9200 -j ACCEPT

再访问。

上面安装的head插件是浏览器与elasticsearch交互的插件,用来在浏览器上查看集群状态,集群doc内容,执行搜索和普通的rest请求。在浏览器访问:http://192.168.112.128:9200/_plugin/head/看到如下界面:

至此 elasticsearch 基本成功搭建。

3.安装Logstash

Logstash的作用是用来收集日志并把日志输出到elasticsearch。

下载Logstash压缩包并解压到 /home/lin/elk/logstash-2.1.1目录,解压后并创建一个config目录后内容如下:

在config目录下新建一个配置文件:

vi config/log4j_to_es.conf

内容如下:

# For detail structure of this file # Set: https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html input {   # For detail config for log4j as input,    # See: https://www.elastic.co/guide/en/logstash/current/plugins-inputs-log4j.html  
 log4j {    
 mode => "server"    
 host => "192.163.112.128"  #Logstash服务器的IP地址    
 port => 4567      #对外端口号,比如log4j配置日志输出到Logstash服务器的端口  
 }
 } 
filter { 
  #Only matched data are send to output.
 } output { 
  # For detail config for elasticsearch as output,    # See: https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html   elasticsearch {
     action => "index"          #The operation on ES     hosts  => "192.168.112.128:9200"   #ElasticSearch服务器的地址与端口,可以是一个数组,集群的时候.     index  => "applog"         #The index to write data to. 
  }
 }

保存文件,运行Logstash:

./bin/logstash agent -f config/log4j_to_es.conf

启动Logstash后看到下面内容:

Logstash startup completed

至此Logstash搭建基本完成。

4.接入Java项目

首先项目肯定需要log4j依赖:

<dependency> 

<groupId>log4j</groupId> 

<artifactId>log4j</artifactId>

<version>1.2.17</version> 

</dependency> 

classpath下创建log4j.properties文件,内容如下:

log4j.rootLogger=INFO,console

# for package com.demo.elk, log would be sent to socket appender.

#demo是对应输出日志的包的包名

log4j.logger.demo=DEBUG, socket

# appender socket

log4j.appender.socket=org.apache.log4j.net.SocketAppender

#logstash配置文件 log4j_to_es.conf配置的端口号

log4j.appender.socket.Port=4567

#logstash服务器IP地址

log4j.appender.socket.RemoteHost=192.168.112.128

log4j.appender.socket.layout=org.apache.log4j.PatternLayout

log4j.appender.socket.layout.ConversionPattern=%d [%-5p] [%l] %m%n

log4j.appender.socket.ReconnectionDelay=10000

# appender console

log4j.appender.console=org.apache.log4j.ConsoleAppender

log4j.appender.console.target=System.out

log4j.appender.console.layout=org.apache.log4j.PatternLayout

log4j.appender.console.layout.ConversionPattern=%d [%-5p] [%l] %m%n

 

Java项目结构:

代码输出日志:

package demo;

import org.apache.log4j.Logger;

public class LogstashDemo {
	private static final Logger LOGGER = Logger.getLogger(LogstashDemo.class);
	public static void main(String[] args) {
	try {
	for(int i=0;i<10;i++) {
	LOGGER.error("Log content to logstash" + i);
	Thread.sleep(500);
	}
	} catch (Exception e) {
	LOGGER.error(e.getMessage(), e);
	}
	}
}

运行程序打印日志,然后浏览器进入 http://192.168.112.128:9200/_plugin/head/

点击一个doc,其中message是日志的源内容。

5.Kibana

 

配置Kibana:

tar -zxvf kibana-4.3.0-linux-x86.tar.gz cd kibana-4.3.0-linux-x86 vi config/kibana.yml

在kibana.yml文件中,编辑如下内容:

server.port: 5601 server.host: “192.168.128.112” elasticsearch.url: http://192.168.128.112:9200 kibana.index: “.kibana”

其中server.port是Kibana对外的端口,server.host是Kibana部署服务器的IP,elasticsearch.url是elasticsearch服务器的IP和端口。

启动Kibana:

进入Kibana的目录,运行 ./bin/kibana

然后在浏览器访问: http://192.168.112.128:5601/

6. Java项目上报日志到ELK

通过log4j配置一个socket appender作为项目输入日志到logstash的方式之外,还有一种更加常用的方式,就是所有项目引入一个统一的Appender,这个appender不影响日志的正常打印,并且它的内部维护一个队列和定时任务调度池,项目在配置了这个appender后将日志提交到这个队列中,调度池中的工作线程再把日志序列化成json插入到redis队列,logstash再配置一个redis作为输入的配置文件,从redis中取读取这些日志再输出到elasticsearch分析。

6.1 RedisAppender

import java.util.ArrayList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * Created by lin on 17-5-16.
 */
public class RedisAppender extends ConsoleAppender {

    private String logCacheKey;

    private int maxPerSize;
    private int coreSize;
    private int timeoutMilliSeconds;
    private int initDelay;
    private int period;

    private ScheduledExecutorService scheduledExecutorService;

    private Queue<LoggingEvent> logQueue = new LinkedBlockingQueue<>();

    public RedisAppender() {
        //安全发布
        synchronized (this) {
            if(scheduledExecutorService == null) {
                scheduledExecutorService = Executors.newScheduledThreadPool(coreSize);
            }
        }
    }

    @Override
    public void activateOptions() {
        super.activateOptions();
        scheduledExecutorService.scheduleAtFixedRate(new LogWorker(maxPerSize, timeoutMilliSeconds, logCacheKey),
                initDelay, period, TimeUnit.MILLISECONDS);
    }

    @Override
    public void append(LoggingEvent event) {
        super.append(event);

        if(logQueue.size() >= maxPerSize) {
            LogLog.warn("log queue size is over max, customer will not push log to the queue");
        } else {
            if(event != null) {
                LogLog.warn("offer logging event to log queue");
                logQueue.offer(event);
            }
        }
    }

    class LogWorker implements Runnable {

        private int maxPerSize;
        private int timeoutMilliSeconds;
        private String logCacheKey;
        private List<LoggingEvent> tempList = new ArrayList<>();

        private JSONEventLayoutV1 jsonEventLayoutV1 = new JSONEventLayoutV1();

        public LogWorker(int maxPerSize, int timeoutMilliSeconds, String logCacheKey) {
            this.maxPerSize = maxPerSize;
            this.timeoutMilliSeconds = timeoutMilliSeconds;
            this.logCacheKey = logCacheKey;
        }

        @Override
        public void run() {
            int idx = 0;
            while (!logQueue.isEmpty() || idx < maxPerSize) {//这里取到一定的量时退出,防止日志量太大时取不完
                LoggingEvent event = logQueue.poll();
                if(event != null) {
                    tempList.add(event);
                }
                idx ++;
            }
            if(!tempList.isEmpty()) {
                rpushBatch(tempList);
            }
            tempList.clear();
        }

        private void rpushBatch(List<LoggingEvent> list) {
            if(list != null && !list.isEmpty()) {
                for(LoggingEvent event : list) {
                    String logJson = jsonEventLayoutV1.format(event);
                    LogLog.warn("push log json string to redis queue:" + logJson);
                    JedisCache.rpush(logCacheKey, logJson, timeoutMilliSeconds);
                }
            }
        }
    }
    public String getLogCacheKey() {
        return logCacheKey;
    }
    public void setLogCacheKey(String logCacheKey) {
        this.logCacheKey = logCacheKey;
    }
    public int getMaxPerSize() {
        return maxPerSize;
    }
    public void setMaxPerSize(int maxPerSize) {
        this.maxPerSize = maxPerSize;
    }
    public int getCoreSize() {
        return coreSize;
    }
    public void setCoreSize(int coreSize) {
        this.coreSize = coreSize;
    }
    public int getTimeoutMilliSeconds() {
        return timeoutMilliSeconds;
    }
    public void setTimeoutMilliSeconds(int timeoutMilliSeconds) {
        this.timeoutMilliSeconds = timeoutMilliSeconds;
    }
    public int getInitDelay() {
        return initDelay;
    }
    public void setInitDelay(int initDelay) {
        this.initDelay = initDelay;
    }
    public int getPeriod() {
        return period;
    }
    public void setPeriod(int period) {
        this.period = period;
    }
}

6.2在log4j.properties配置这个appender

log4j.rootLogger = INFO, REDIS

log4j.appender.consoleAppender = org.apache.log4j.ConsoleAppender
log4j.appender.consoleAppender.layout = org.apache.log4j.PatternLayout
log4j.appender.consoleAppender.layout.ConversionPattern = %-4r [%t] %5p %c %x - %m - [%X{userName}]%n

log4j.appender.REDIS= com.test.RedisAppender
log4j.appender.REDIS.layout = org.apache.log4j.PatternLayout
log4j.appender.REDIS.layout.ConversionPattern = %-4r [%t] %5p %c %x - %m%n
log4j.appender.REDIS.logCacheKey = logstash-
log4j.appender.REDIS.maxPerSize = 100
log4j.appender.REDIS.coreSize = 2
log4j.appender.REDIS.timeoutMilliSeconds = 10000
log4j.appender.REDIS.initDelay = 3000
log4j.appender.REDIS.period = 1000

6.3 logstash配置redis作为输入

新加个配置文件 redis_to_es.conf:

input {
  redis {
    data_type => "list" #logstash redis插件工作方式
    key => "mycompany-logstash-" #监听的键值
    host => "192.168.112.128" #redis地址
    port => 6379 #redis端口号
    password => "123" #如果有安全认证,此项为密码
  }
}
filter {
  #Only matched data are send to output.
}
output {
  elasticsearch {
    action => "index"          #The operation on ES
    hosts  => "192.168.112.128:9200"   #ElasticSearch服务器的地址与端口,可以是一个数组,集群的时候.
    index  => "applog"         #The index to write data to.
  }
}

6.4 日志触发

import org.apache.log4j.Logger;
public class App {
    private static Logger log = Logger.getLogger(App.class);
    public static void main( String[] args ) {
        for(int i=0;i<100;i++) {
            log.info("log message to redis:" + i);
        }
    }
}

6.5 日志收集结果

去Kibana中看最新的日志:

转载于:https://my.oschina.net/ChiLin/blog/1574789

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值