1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
|
# frozen_string_literal: true
require "json"
require "fileutils"
require "pathname"
require "delegate"
module Sentry
# DebugStructuredLogger is a logger that captures structured log events to a file for debugging purposes.
#
# It can optionally also send log events to Sentry via the normal structured logger if logging
# is enabled.
class DebugStructuredLogger < SimpleDelegator
DEFAULT_LOG_FILE_PATH = File.join("log", "sentry_debug_logs.log")
attr_reader :log_file, :backend
def initialize(configuration)
@log_file = initialize_log_file(
configuration.structured_logging.file_path || DEFAULT_LOG_FILE_PATH
)
@backend = initialize_backend(configuration)
super(@backend)
end
# Override all log level methods to capture events
%i[trace debug info warn error fatal].each do |level|
define_method(level) do |message, parameters = [], **attributes|
log_event = capture_log_event(level, message, parameters, **attributes)
backend.public_send(level, message, parameters, **attributes)
log_event
end
end
def log(level, message, parameters:, **attributes)
log_event = capture_log_event(level, message, parameters, **attributes)
backend.log(level, message, parameters: parameters, **attributes)
log_event
end
def capture_log_event(level, message, parameters, **attributes)
log_event_json = {
timestamp: Time.now.utc.iso8601,
level: level.to_s,
message: message,
parameters: parameters,
attributes: attributes
}
File.open(log_file, "a") { |file| file << JSON.dump(log_event_json) << "\n" }
log_event_json
end
def logged_events
File.readlines(log_file).map do |line|
JSON.parse(line)
end
end
def clear
File.write(log_file, "")
if backend.respond_to?(:config)
backend.config.sdk_logger.debug("DebugStructuredLogger: Cleared events from #{log_file}")
end
end
private
def initialize_backend(configuration)
if configuration.enable_logs
StructuredLogger.new(configuration)
else
# Create a no-op logger if logging is disabled
NoOpLogger.new
end
end
def initialize_log_file(log_file_path)
log_file = Pathname(log_file_path)
FileUtils.mkdir_p(log_file.dirname) unless log_file.dirname.exist?
log_file
end
# No-op logger for when structured logging is disabled
class NoOpLogger
%i[trace debug info warn error fatal log].each do |method|
define_method(method) { |*args, **kwargs| nil }
end
end
end
end
|