mirror of
https://github.com/discourse/discourse.git
synced 2025-04-19 16:29:05 +08:00

This commit rewrites `DiscourseLogstashLogger` to not be an instance of `LogstashLogger`. The reason we don't want it to be an instance of `LogstashLogger` is because we want the new logger to be chained to Logster's logger which can then pass down useful information like the request's env and error backtraces which Logster has already gathered. Note that this commit does not bother to maintain backwards compatibility and drops the `LOGSTASH_URI` and `UNICORN_LOGSTASH_URI` ENV variables which were previously used to configure the destination in which `logstash-logger` would send the logs to. Instead, we introduce the `ENABLE_LOGSTASH_LOGGER` ENV variable to replace both ENV and remove the need for the log paths to be specified. Note that the previous feature was considered experimental as stated in d888d3c54c4744d52b9d21d3728f5d6dbc132cde and the new feature should be considered experimental as well. The code may be moved into a plugin in the future.
105 lines
3.0 KiB
Ruby
105 lines
3.0 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "json"
|
|
require "socket"
|
|
require_relative "git_utils"
|
|
|
|
class DiscourseLogstashLogger < Logger
|
|
PROCESS_PID = Process.pid
|
|
HOST = Socket.gethostname
|
|
GIT_VERSION = GitUtils.git_version
|
|
|
|
attr_accessor :customize_event, :type
|
|
|
|
# Creates a new logger instance.
|
|
#
|
|
# @param logdev [String, IO, nil] The log device. This can be one of:
|
|
# - A string filepath: entries are written to the file at that path. If the file exists, new entries are appended.
|
|
# - An IO stream (typically +$stdout+, +$stderr+, or an open file): entries are written to the given stream.
|
|
# - nil or File::NULL: no entries are written.
|
|
# @param type [String] The type of log messages. This will add a `type` field to all log messages.
|
|
# @param customize_event [Proc, nil] A proc that customizes the log event before it is written to the log device.
|
|
# The proc is called with a hash of log event data and can be modified in place.
|
|
#
|
|
# @return [Logger] A new logger instance with the specified log device and type.
|
|
def self.logger(logdev:, type:, customize_event: nil)
|
|
logger = self.new(logdev)
|
|
logger.type = type
|
|
logger.customize_event = customize_event if customize_event
|
|
logger
|
|
end
|
|
|
|
# :nodoc:
|
|
def add(*args, &block)
|
|
add_with_opts(*args, &block)
|
|
end
|
|
|
|
ALLOWED_HEADERS_FROM_ENV = %w[
|
|
REQUEST_URI
|
|
REQUEST_METHOD
|
|
HTTP_HOST
|
|
HTTP_USER_AGENT
|
|
HTTP_ACCEPT
|
|
HTTP_REFERER
|
|
HTTP_X_FORWARDED_FOR
|
|
HTTP_X_REAL_IP
|
|
]
|
|
|
|
# :nodoc:
|
|
def add_with_opts(severity, message = nil, progname = nil, opts = {}, &block)
|
|
return true if @logdev.nil? || severity < @level
|
|
|
|
progname = @progname if progname.nil?
|
|
|
|
if message.nil?
|
|
if block_given?
|
|
message = yield
|
|
else
|
|
message = progname
|
|
progname = @progname
|
|
end
|
|
end
|
|
|
|
event = {
|
|
"message" => message,
|
|
"severity" => severity,
|
|
"severity_name" => Logger::SEV_LABEL[severity],
|
|
"pid" => PROCESS_PID,
|
|
"type" => @type.to_s,
|
|
"host" => HOST,
|
|
"git_version" => GitUtils.git_version,
|
|
}
|
|
|
|
# Only log backtrace and env for Logger::WARN and above.
|
|
# Backtrace is just noise for anything below that.
|
|
if severity >= Logger::WARN
|
|
if (backtrace = opts&.dig(:backtrace)).present?
|
|
event["backtrace"] = backtrace
|
|
end
|
|
|
|
if (env = opts&.dig(:env)).present?
|
|
ALLOWED_HEADERS_FROM_ENV.each do |header|
|
|
event["request.headers.#{header.downcase}"] = opts[:env][header]
|
|
end
|
|
end
|
|
end
|
|
|
|
if message.start_with?("{") && message.end_with?("}")
|
|
begin
|
|
parsed = JSON.parse(message)
|
|
event["message"] = parsed.delete("message") if parsed["message"]
|
|
event.merge!(parsed)
|
|
event
|
|
rescue JSON::ParserError
|
|
# Do nothing
|
|
end
|
|
end
|
|
|
|
@customize_event.call(event) if @customize_event
|
|
|
|
@logdev.write("#{event.to_json}\n")
|
|
rescue Exception => e
|
|
STDERR.puts "Error logging message in DiscourseLogstashLogger: #{message} (#{e.message})\n#{e.backtrace.join("\n")}"
|
|
end
|
|
end
|