LogStashLogger 扩展了 Ruby 的Logger
类以直接记录到 Logstash。它支持以 Logstash JSON 格式写入各种输出。这是对写入文件或系统日志的改进,因为 Logstash 可以直接接收结构化数据。
可以通过 UDP 或 TCP/SSL 连接直接写入 Logstash 侦听器。
可以写入文件、Redis、Kafka、Kinesis、Firehose、unix 套接字、syslog、stdout 或 stderr。
Logger 可以采用字符串消息、哈希值、 LogStash::Event
、对象或 JSON 字符串作为输入。
事件会自动填充消息、时间戳、主机和严重性。
以 Logstash JSON 格式写入,但也支持其他格式。
可以写入多个输出。
日志消息会被缓冲并在出现连接问题时自动重新发送。
通过配置轻松与 Rails 集成。
将此行添加到应用程序的 Gemfile 中:
gem 'logstash-logger'
然后执行:
$ bundle
或者自己安装:
$ gem install logstash-logger
require 'logstash-logger'# 默认为 0.0.0.0 上的 UDPlogger = LogStashLogger.new(port: 5228)# 显式指定主机和类型(UDP 或 TCP)udp_logger = LogStashLogger.new(type: :udp, host: 'localhost' ,端口:5228)tcp_logger = LogStashLogger.new(类型::tcp,主机:'localhost',端口:第5229章)syslog_logger = LogStashLogger.new(类型: :syslog)redis_logger = LogStashLogger.new(类型: :redis)kafka_logger = LogStashLogger.new(类型::kafka)stdout_logger = LogStashLogger.new(类型::stdout)stderr_logger = LogStashLogger.new(类型::stderr)io_logger = LogStashLogger.new(类型::io, io: io )# 使用不同的格式cee_logger = LogStashLogger.new( 类型::TCP, 主机:'logsene-receiver-syslog.sematext.com', 端口:514, 格式化程序: :cee_syslog)custom_formatted_logger = LogStashLogger.new( 类型::redis, 格式化程序:MyCustomFormatter)lambda_formatted_logger = LogStashLogger.new( 类型::标准输出, 格式化程序:->(严重性、时间、程序名称、消息) { "[#{progname}] #{msg}" })ruby_default_formatter_logger = LogStashLogger.new( 类型::文件, 路径: 'log/development.log', formatter: ::Logger::Formatter)# 将消息发送到多个输出。每个输出都将具有相同的格式。# Syslog 不能作为输出,因为它需要单独的 logger.multi_delegating_logger = LogStashLogger.new( 类型::multi_delegator, 输出:[{ 类型::file,路径:'log/development.log' },{ 类型::udp,主机:'localhost',端口:5228 } ])# 平衡多个输出之间的消息。# 与多委托人相同,但随机选择一个输出来发送每条消息。balancer_logger = LogStashLogger.new( 类型::平衡器, 输出:[{类型::udp,主机:'host1',端口:5228},{类型::udp,主机:'host2',端口:5228} ])# 向多个记录器发送消息。# 如果您需要将不同格式发送到不同的输出,请使用此。# 如果您需要记录到系统日志,则必须使用此。multi_logger = LogStashLogger.new( 类型::multi_logger, 输出:[{ 类型::文件,路径:'log/development.log',格式化程序:::Logger::Formatter },{ 类型::tcp,主机:'localhost',端口:5228,格式化程序::json } ])# 以下消息写入 UDP 端口 5228:logger.info 'test'# {"message":"test","@timestamp":"2014-05-22T09:37:19.204-07:00", "@version":"1","severity":"INFO","host":"[主机名]"}logger.error '{"message": "error"}'# {"message":"error","@timestamp":"2014-05-22T10:10:55.877-07:00","@version":"1" ,"severity":"ERROR","host":"[hostname]"}logger.debug message: 'test', foo: 'bar'# {“message”:“test”,“foo”:“bar”,“@timestamp”:“2014-05-22T09:43:24.004-07:00”,“@version”:“1”,“严重性” :"DEBUG","host":"[主机名]"}logger.warn LogStash::Event.new(message: 'test', foo: 'bar')# {"message":"test","foo":"bar","@timestamp":"2014-05-22T16:44:37.364Z","@version":"1","严重程度":"警告","主机":"[主机名]"}# 已标记的logginglogger.tagged('foo') { logger.fatal('bar') }# {“message”:“bar”,“@timestamp”:“2014-05-26T20:35:14.685-07:00”,“@version”:“1”,“严重性”:“致命”,“主机” :"[主机名]","标签":["foo"]}
您可以使用 URI 而不是哈希来配置 Logstash 记录器。这在 Heroku 等环境中非常有用,您可能希望从环境中读取配置值。 URI 方案为type://host:port/path?key=value
。下面给出了一些示例 URI 配置。
udp://localhost:5228 tcp://localhost:5229 unix:///tmp/socket file:///path/to/file redis://localhost:6379 kafka://localhost:9092 stdout:/ stderr:/
将 URI 传递到您的 Logstash 记录器中,如下所示:
# 从环境变量中读取 URIlogger = LogStashLogger.new(uri: ENV['LOGSTASH_URI'])
为了让 Logstash 正确接收和解析事件,您需要配置并运行使用json_lines
编解码器的侦听器。例如,要在端口 5228 上通过 UDP 接收事件:
输入 { udp {主机=>“0.0.0.0”端口=>5228codec=>json_lines }}
文件和 Redis 输入应使用json
编解码器。有关更多信息,请阅读 Logstash 文档。
有关更多配置示例,请参阅示例目录。
如果您使用 TCP,则可以选择在初始化时将 SSL 证书添加到选项哈希中。
LogStashLogger.new(类型::tcp,端口:5228,ssl_certificate:“/path/to/certificate.crt”)
SSL 证书和密钥可以使用以下方式生成
openssl req -x509 -batch -nodes -newkey rsa:2048 -keyout logstash.key -out logstash.crt
您还可以在没有证书的情况下启用 SSL:
LogStashLogger.new(类型::tcp,端口:5228,ssl_enable:true)
指定 SSL 上下文以更好地控制行为。例如设置验证模式:
ctx = OpenSSL::SSL::SSLContext.newctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_NONE)LogStashLogger.new(类型::tcp,端口:5228,ssl_context:ctx)
SSL 需要以下 Logstash 配置:
输入 { tcp {主机=>“0.0.0.0”端口=>5228codec=>json_inesssl_enable=>truessl_cert=>“/path/to/certificate.crt”ssl_key=>“/path/to/key.key” }}
默认情况下启用主机名验证。无需进一步配置,提供给:host
的主机名将用于验证服务器的证书身份。
如果您不传递:ssl_context
或向:verify_hostname
选项传递 false 值,则不会进行主机名验证。
通过:host
选项验证主机名
ctx = OpenSSL::SSL::SSLContext.newctx.cert = '/path/to/cert.pem'ctx.verify_mode = OpenSSL::SSL::VERIFY_PEERLogStashLogger.new 类型::TCP, 主机:'logstash.example.com' 端口:5228, ssl_上下文:ctx
验证主机名与:host
选项不同
LogStashLogger.new 类型::TCP, 主机:'1.2.3.4' 端口:5228, ssl_context:ctx, verify_hostname: 'server.example.com'
显式禁用主机名验证
LogStashLogger.new 类型::TCP, 主机:'1.2.3.4' 端口:5228, ssl_context:ctx, 验证主机名: false
默认情况下, LogStashLogger
将记录以下格式的 JSON 对象。
{ "message":"一些消息", "@timestamp":"2015-01-29T10:43:32.196-05:00", "@version":"1", "severity":"INFO", "host ":"主机名"}
某些应用程序可能需要将附加元数据附加到每条消息。可以通过在LogStashLogger
配置中指定customize_event
块来直接操作LogStash::Event
。
config = LogStashLogger.configure 做 |config| config.customize_event do |event|event["other_field"] = "some_other_value" 结束
此配置将产生以下输出。
{“message”:“一些消息”,“@timestamp”:“2015-01-29T10:43:32.196-05:00”,“@version”:“1”,“严重性”:“INFO”,“主机": "主机名","other_field": "some_other_value"}
该块具有对事件的完全访问权限,因此您可以删除字段、修改现有字段等。例如,要删除默认时间戳:
config = LogStashLogger.configure 做 |config| config.customize_event do |event|event.remove('@timestamp') 结束
您还可以在创建记录器时将可调用对象(lambda 或 proc)传递给customize_event
选项,从而在每个记录器的基础上自定义事件:
LogStashLogger.new(customize_event: ->(event){ event['other_field'] = 'other_field' })
对于与远程服务建立连接的设备,日志消息在内部缓冲并在后台线程中刷新。如果出现连接问题,消息将保存在缓冲区中并自动重新发送,直到成功为止。支持批量写入的输出(Redis 和 Kafka)将从缓冲区批量写入日志消息。此功能是使用 Stud::Buffer 的分支来实现的。您可以通过将以下选项传递给 LogStashLogger 来配置其行为:
:buffer_max_items - 刷新之前缓冲的最大项目数。默认为 50。
:buffer_max_interval - 刷新之间等待的最大秒数。默认为 5。
:drop_messages_on_flush_error - 出现刷新错误时删除消息。默认为 false。
:drop_messages_on_full_buffer - 当缓冲区已满时删除消息。默认为 true。
:sync - 每次收到消息时刷新缓冲区(阻塞)。默认为 false。
:buffer_flush_at_exit - 退出程序时刷新消息。默认为 true。
:buffer_logger - 用于写入缓冲区调试/错误消息的记录器。默认为无。
您可以通过设置sync = true
来关闭缓冲。
请注意此行为的以下警告:
重试时可能会发送重复的日志消息。对于像 Redis 和 Kafka 这样批量写入的输出,整个批次可能会被重新发送。如果这是一个问题,您可以向每个事件添加 UUID 字段以唯一标识它。您可以在customize_event
块中执行此操作,也可以使用logstash 的UUID 过滤器来执行此操作。
仍然有可能丢失日志消息。 Ruby 不会立即检测到 TCP/UDP 连接问题。在我的测试中,Ruby 花了大约 4 秒的时间才注意到接收端已关闭并开始引发异常。由于 TCP/UDP 上的 Logstash 侦听器不会确认收到的消息,因此无法知道要重新发送哪些日志消息。
当sync
关闭时,Ruby 可能会在写入 IO 设备之前在内部缓冲数据。这就是为什么即使 LogStashLogger 的缓冲区定期刷新,您也可能看不到立即写入 UDP 或 TCP 套接字的消息。
默认情况下,当缓冲区已满时,消息将被丢弃。如果输出源关闭时间过长或接收日志消息的速度过快,则可能会发生这种情况。如果您的应用程序突然终止(例如,由于 SIGKILL 或断电),整个缓冲区将丢失。
您可以通过增加buffer_max_items
(以便缓冲区中可以保存更多事件)和减少buffer_max_interval
(以减少刷新之间的等待时间)来降低消息丢失的可能性。当日志消息在缓冲区中累积时,这会增加应用程序的内存压力,因此请确保为进程分配了足够的内存。
如果您不想在缓冲区满时丢失消息,可以设置drop_messages_on_full_buffer = false
。请注意,如果缓冲区已满,任何传入的日志消息都将被阻塞,这可能是不可取的。
所有记录器输出都支持sync
设置。这类似于 Ruby IO 对象上的“同步模式”设置。当设置为true
时,输出将立即刷新并且不会在内部缓冲。通常,对于连接到远程服务的设备来说,缓冲是一件好事,因为它可以提高性能并减少影响程序的错误的可能性。对于这些设备, sync
默认为false
,建议保留默认值。您可能需要打开同步模式进行测试,例如,如果您想在写入日志消息后立即查看日志消息。
建议为文件和 Unix 套接字输出打开同步模式。这可确保来自不同线程或进程的日志消息正确写入不同的行。
有关更多详细信息,请参阅#44。
如果在向设备写入消息时发生异常,则会使用内部记录器记录该异常。默认情况下,这会记录到 $stderr。您可以通过设置LogStashLogger.configuration.default_error_logger
或在实例化 LogStashLogger 时在:error_logger
配置键中传递您自己的记录器对象来更改错误记录器。
LogStashLogger 提供对 Rails 风格的记录器静默的支持。该实现是从 Rails 中提取的,但没有依赖项,因此可以在 Rails 应用程序之外使用。该接口与 Rails 中的接口相同:
logger.silence(temporary_level) 做 ...结尾
默认情况下,LogStashLogger 创建一个扩展 Ruby 内置Logger
类的记录器。如果您需要不同的记录器实现,则可以通过使用logger_class
选项传入类来使用不同的类。
请注意,对于 syslog, Syslog::Logger
类是必需的且无法更改。
支持 Rails 4.2 和 5.x。
默认情况下,每条 Rails 日志消息都将以LogStash::Event
JSON 格式写入logstash。
对于最少的、更结构化的 Logstash 事件,请尝试以下 gem 之一:
记录
码垛机
目前,这些 gem 输出一个 JSON 字符串,然后由 LogStashLogger 解析。这些 gem 的未来版本可能会与 LogStashLogger 进行更深入的集成(例如,通过直接编写LogStash::Event
对象)。
将以下内容添加到您的config/environments/production.rb
:
# 可选,Rails 将默认设置为 :infoconfig.log_level = :debug# 可选,Rails 4 在开发中默认为 true,在生产中默认为 falseconfig.autoflush_log = true# 可选,使用 URI 进行配置。对 Herokuconfig.logstash.uri 很有用 = ENV['LOGSTASH_URI']# 可选。默认为:json_lines。如果有多个输出,#它们将共享相同的格式化程序。config.logstash.formatter = :json_lines#可选,用于记录写入错误的记录器。默认记录到 $stderrconfig.logstash.error_logger = Logger.new($stderr)# 可选,刷新之前要缓冲的最大项目数。默认为 50config.logstash.buffer_max_items = 50# 可选,刷新之间等待的最大秒数。默认为 5config.logstash.buffer_max_interval = 5# 可选,发生连接错误时丢弃消息。默认为 falseconfig.logstash.drop_messages_on_flush_error = false# 可选,当缓冲区已满时删除消息。默认为 trueconfig.logstash.drop_messages_on_full_buffer = true
# 可选,默认为 '0.0.0.0'config.logstash.host = 'localhost'# 可选,默认为 :udp.config.logstash.type = :udp# 必需,连接的端口config.logstash.port = 5228
# 可选,默认为 '0.0.0.0'config.logstash.host = 'localhost'# 必需,连接的端口config.logstash.port = 5228# 必需config.logstash.type = :tcp# 可选,启用SSLconfig.logstash。 ssl_启用=真
# 必需的config.logstash.type = :unix# 必需的config.logstash.path = '/tmp/sock'
如果您使用的是 Ruby 1.9,请将Syslog::Logger
v2 添加到您的 Gemfile 中:
gem 'SyslogLogger', '2.0'
如果您使用的是 Ruby 2+, Syslog::Logger
已内置到标准库中。
# 必需的config.logstash.type = :syslog# 可选。默认为 'ruby'config.logstash.program_name = 'MyApp'# 可选的默认设施级别。仅适用于 Ruby 2+config.logstash.facility = Syslog::LOG_LOCAL0
将 redis gem 添加到您的 Gemfile 中:
gem 'redis'
# 必需config.logstash.type = :redis# 可选,默认为'logstash'列表config.logstash.list = 'logstash'# 所有其他选项都会传入Redis客户端# 支持的选项包括主机、端口、路径、密码, url# 示例:# 可选,Redis 将默认为 localhostconfig.logstash.host = 'localhost'# 可选,Redis 将默认为端口 6379config.logstash.port = 6379
将海神 gem 添加到您的 Gemfile 中:
gem 'poseidon'
# 必需config.logstash.type = :kafka# 可选,默认为'logstash' topicconfig.logstash.path = 'logstash'# 可选,默认为'logstash-logger' Producerconfig.logstash. Producer = 'logstash-logger '# 可选,默认为 localhost:9092 host/portconfig.logstash.hosts = ['localhost:9092']# 可选,默认为1s backoffconfig.logstash.backoff = 1
将 aws-sdk gem 添加到您的 Gemfile 中:
# aws-sdk >= 3.0 gem 'aws-sdk-kinesis' # aws-sdk < 3.0 gem 'aws-sdk'
# 必需config.logstash.type = :kinesis# 可选,默认为“logstash”streamconfig.logstash.stream = 'my-stream-name'# 可选,默认为“us-east-1”config.logstash.aws_region = 'us-west-2'# 可选,默认为 AWS_ACCESS_KEY_ID 环境变量config.logstash.aws_access_key_id = 'ASKASKHLD12341'# 可选,默认为 AWS_SECRET_ACCESS_KEY 环境变量config.logstash.aws_secret_access_key = 'ASKASKHLD1234123412341234'
将 aws-sdk gem 添加到您的 Gemfile 中:
# aws-sdk >= 3.0 gem 'aws-sdk-firehose' # aws-sdk < 3.0 gem 'aws-sdk'
# 必需的config.logstash.type = :firehose# 可选,将默认为“logstash”传输流config.logstash.stream = 'my-stream-name'# 可选,将默认为AWS默认区域配置 chainconfig.logstash.aws_region = ' us-west-2'# 可选,默认为 AWS 默认凭证提供程序 chainconfig.logstash.aws_access_key_id = 'ASKASKHLD12341'# 可选,默认为 AWS 默认凭证提供程序 chainconfig.logstash.aws_secret_access_key = 'ASKASKHLD1234123412341234'
# 必填config.logstash.type = :file# 可选,默认为Rails日志路径config.logstash.path = 'log/Production.log'
# 必需的config.logstash.type = :io# 必需的config.logstash.io = io
# 必需的config.logstash.type = :multi_delegator# 必需的config.logstash.outputs = [ {类型::文件,路径:'日志/生产.log' }, {类型::udp,端口:5228,主机:'localhost' }]
# 必需的config.logstash.type = :multi_logger# 必需的。每个记录器可能有自己的 formatter.config.logstash.outputs = [ {类型::文件,路径:'日志/生产.log',格式化程序:::Logger::Formatter }, {类型::udp,端口:5228,主机:'localhost' }]
在 Web 应用程序中,您可以使用 RequestStore 中间件记录来自 HTTP 请求的数据(例如标头)。以下示例假设为 Rails。
# 在 Gemfilegem 'request_store' 中
# 在 application.rbLogStashLogger.configure 中执行 |config| config.customize_event do |event|event["session_id"] = RequestStore.store[:load_balancer_session_id] 结束
#在应用程序/控制器/application_controller.rbbefore_filter中:track_load_balancer_session_iddef track_load_balancer_session_id RequestStore.store[:load_balancer_session_id] = request.headers["X-LOADBALANCER-SESSIONID"]end
如果您的应用程序分叉(这在许多 Web 服务器中很常见),您将需要管理 LogStashLogger 实例上的资源清理。实例方法#reset
可用于此目的。以下是与 Rails 一起使用的几种常见 Web 服务器的示例配置:
乘客:
::PhusionPassenger.on_event(:starting_worker_process) 做 |forked| Rails.logger.resetend
美洲狮:
# 在 config/puma.rbon_worker_boot 中执行 Rails.logger.resetend
独角兽
# 在 config/unicorn.rbafter_fork 中执行 |server,worker| Rails.logger.resetend
已验证可与:
核磁共振红宝石 2.2 - 2.5
JRuby 9.x
鲁比纽斯
Ruby 版本 < 2.2 已停产,不再受支持。
这取决于您的具体需求,但大多数应用程序应使用默认值 (UDP)。以下是每种类型的优点和缺点:
UDP 比 TCP 更快,因为它是异步的(即发即弃)。但是,这意味着日志消息可能会被丢弃。这对于许多应用程序来说都是可以的。
TCP 验证是否已通过双向通信接收到每条消息。它还支持 SSL 通过网络安全传输日志消息。如果 TCP 侦听器负载过重,这可能会减慢您的应用程序的速度。
文件使用起来很简单,但您将不得不担心日志轮换和磁盘空间不足。
写入 Unix 套接字比写入 TCP 或 UDP 端口更快,但只能在本地工作。
写入 Redis 对于生成大量日志的分布式设置很有用。然而,您将有另一个移动部分,并且必须担心 Redis 内存不足。
仅建议出于调试目的写入标准输出。
有关 UDP 与 TCP 的更详细讨论,我建议阅读这篇文章:UDP 与 TCP
如果您使用的是 Ruby IO 对象支持的设备(例如文件、UDP 套接字或 TCP 套接字),请注意 Ruby 保留其自己的内部缓冲区。尽管 LogStashLogger 会缓冲消息并定期刷新它们,但写入 IO 对象的数据可以由 Ruby 内部无限期地缓冲,甚至可能直到程序终止才写入。如果这让您烦恼或者您需要立即查看日志消息,您唯一的办法就是设置sync: true
选项。
您的应用程序可能正在尝试记录未以有效方式编码的数据。当发生这种情况时,Ruby 的标准 JSON 库将引发异常。您可以通过更换不同的 JSON 编码器(例如 Oj)来克服这个问题。使用 oj_mimic_json gem 来使用 Oj 进行 JSON 生成。
Heroku 建议安装rails_12factor,以便将日志发送到STDOUT。不幸的是,这会覆盖 LogStashLogger,从而阻止日志发送到其配置的目的地。解决方案是从 Gemfile 中删除rails_12factor
。
这很可能不是 LogStashLogger 的问题,而是改变Rails.logger
日志级别的不同 gem 的问题。如果您使用的是 Puma 等线程服务器,这种情况尤其可能发生,因为 gem 经常以非线程安全的方式更改Rails.logger
的日志级别。有关详细信息,请参阅#17。
如果您使用 UDP 输出并向 Logstash 侦听器写入数据,则很可能会在 Logstash 侦听器的 UDP 实现中遇到错误。目前没有已知的修复方法。有关详细信息,请参阅#43。
使用 TCP 或 UDP 的一个已知缺点是总消息大小限制为 65535 字节。要解决此问题,您必须通过设置最大消息大小来截断消息:
LogStashLogger.configure 执行 |config| config.max_message_size = 2000end
这将仅截断 LogStash 事件的message
字段。因此,请确保将最大消息大小设置为明显小于 65535 字节,以便为其他字段腾出空间。
Rails 3.2、MRI Ruby < 2.2 和 JRuby 1.7 不再受支持,因为它们已停产。如果您使用的是较旧版本的 Ruby,则需要使用 0.24 或更低版本。
source
事件键已替换为host
,以更好地匹配最新的logstash。
(host, port, type)
构造函数已被弃用,取而代之的是选项哈希构造函数。
LogStash::Event
从 1.2+ 版本开始使用 v1 格式。如果您使用的是 v1,则需要安装 LogStashLogger 版本 0.4+。这与使用 v0 格式的旧LogStash::Event
v1.1.5 不向后兼容。
这个 gem 的早期版本(<= 0.2.1)仅实现了 TCP 连接。较新的版本 (>= 0.3) 还实现了 UDP,并将其用作新的默认值。请注意,如果您使用默认构造函数并且仍然需要 TCP,则应该添加一个附加参数:
# 现在默认为 UDP 而不是 TCPlogger = LogStashLogger.new('localhost', 5228)# 显式指定 TCP 而不是 UDPlogger = LogStashLogger.new('localhost', 5228, :tcp)
大卫·巴特勒
pctj101
加里·雷尼
尼克·埃蒂尔
阿伦·马布里
简·舒尔特
科特·普雷斯顿
克里斯·布拉奇利
菲利克斯·贝希斯坦
瓦季姆·卡扎科夫
阿尼尔·雷姆图拉
尼基塔·沃罗贝
火男孩1919
迈克·冈德罗伊
维塔利·戈罗德茨基
考特兰·考德威尔
比贝克·什雷斯塔
亚历克斯·伊阿努斯
克雷格·里德
格拉齐格
兰斌
若奥·费尔南德斯
酷猫王
谢尔盖·皮扬科夫
亚历克·霍伊
阿列克谢·克拉斯诺佩罗夫
加布里埃尔·德·奥利维拉
弗拉迪斯拉夫·夏布鲁克
马图斯·瓦库拉
分叉它
创建您的功能分支( git checkout -b my-new-feature
)
提交您的更改( git commit -am 'Add some feature'
)
推送到分支( git push origin my-new-feature
)
创建新的拉取请求