Rails应用将日志送到ELK中

Rails ELK integration

Posted by leasy on October 29, 2019

“Rails日志发送到ELK平台”

最近在研究Rails如何将日志送到ELK中,这里记录下。我会创建

使用工具

准备工作

  • 配置ELK,我是用Docker来配置和运行ELK工具的,如何配置参考TBD
  • 创建一个Rails项目,运行
    $ rails new app
    

    创建一个结构完整的Rails 应用

  • 安装依赖库,打开Gemfile,添加
    gem 'lograge'
    gem 'logstash-event'
    gem 'logstash-logger'
    

    三个依赖,运行

    $ bundle install
    

    命令安装依赖

格式化Rails日志

首先在config/initializers添加一个配置文件logstash.rb,添加下面的配置

    Rails.application.configure do
        config.lograge.enabled = true
        config.lograge.formatter = Lograge::Formatters::Logstash.new
    end

这个时候运行程序,访问localhost:3000输出的结果应该是

{
    "method": "GET",
    "path": "/",
    "format": "json",
    "controller": "index",
    "action": "/",
    "status": 200,
    "duration": 27.2,
    "view": 0.22,
    "db": 11.32,
    "@timestamp": "2019-10-30T10:19:14.766Z",
    "@version": "1",
    "message": "[200] GET / "
}

如果我们需要在日志中添加更多的字段,那么可以在application_controller.rb中添加方法

    def append_info_to_payload(payload)
        super
        payload[:uuid] =  request.uuid
        payload[:remote_ip] = request.remote_ip
    end

然后在logstash.rb中继续添加配置文件

config.lograge.custom_options = lambda do |event|
    {
        :uuid => event.payload[:uuid],
        :remote_ip => event.payload[:remote_ip]
    }
end

这样子配置完,输出的日志格式就变成了

{
    "method": "GET",
    "path": "/",
    "format": "json",
    "controller": "index",
    "action": "/",
    "status": 200,
    "duration": 27.2,
    "view": 0.22,
    "db": 11.32,
    "@timestamp": "2019-10-30T10:19:14.766Z",
    "@version": "1",
    "message": "[200] GET / ",
    "uuid": "0x908fjasq09qjfsoidapfu",
    "remote_ip": "127.0.0.1"
}

多了两个自定义的字段。

日志送到logstash

logstash的配置和使用在另外一篇文章介绍,这里就找了一个简单的配置文件说明要送到logstash需要做的配置

input {
    stdin {}
  file {
    type=> 'application'
    path=>'~/out.log'
    codec=>'json'
  }
}

output {
  stdout {}
  elasticsearch {
    cluster=> 'logstash'
    protocol => http
  }
}

然后替换lograge的logger

config.lograge.logger = LogStashLogger.new(type: :tcp, host: localhost, port: 5288)

这样子就可以把日志送到logstash,因为ELK已经配置好,所以可以在kibana上面看到日志。默认的日志是”logstash-日期”,在kibana中新建一个”logstash-*“的index pattern就可以搜索到输出的日志。

替换Rails.logger

在Rails中打印日志通常是用

Rails.logger.info("some logs")

来打印日志。 尝试了一下在application.rb中用

config.log = LogStashLogger.new(type: :tcp, host: localhost, port: 5288)

发现会报错,所以就创建了一个module,里面持有一个logstash-logger对象

module LogHelper
    Logger = LogStashLogger.new(type: :tcp, host: localhost, port: 5288)
end

用LogHelper::Logger的方式来使用logstash logger,比如

LogHelper::Logger.info 'some logger'

但是这样做使用的是logstash-logger默认的输出格式,不会受到上面lograge配置的影响,所以需要配置logstash-logger

module AapLoggerHelper
    LogStashLogger.configure do |config|
        config.customize_event do |event|
          event["log_format"] = "json"
          event["log_level"] = "info"
        end
    end
    Logger = LogStashLogger.new(type: :tcp, host: localhost, port: 5288)
end

这样子就可以定义自己想要输出的格式了。

结论

这篇文章简单介绍如何在Rails中把日志通过logstash送到elastic中,然后在Kibana上进行搜索和分析,首先是引入相关依赖,然后是配置lograge和logstash,这个时候已经可以把访问日志通过logstash送到elastic中,然后介绍了如何替换默认的log,将日志输出的logstash中。 不过还有很多地方没有介绍,如何处理异常,如何记录db的日志,而且感觉创建log的方式不够优雅,还有很多需要改进。