diff --git a/CHANGELOG.md b/CHANGELOG.md index 3637dfc1c..7f7b7fc39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ ## Unreleased +### Feature + +- STDLIB Logger Support - send any instance of logger to sentry. ([#2653](https://github.com/getsentry/sentry-ruby/pull/2653)) + +### Bug Fixes - Skip creating `LogEventBuffer` if logging is not enabled ([#2652](https://github.com/getsentry/sentry-ruby/pull/2652)) ## 5.25.0 diff --git a/sentry-ruby/lib/sentry-ruby.rb b/sentry-ruby/lib/sentry-ruby.rb index 8d3f0578e..a2a43b4e3 100644 --- a/sentry-ruby/lib/sentry-ruby.rb +++ b/sentry-ruby/lib/sentry-ruby.rb @@ -690,3 +690,4 @@ def dependency_installed?(name) require "sentry/graphql" require "sentry/faraday" require "sentry/excon" +require "sentry/std_lib_logger" diff --git a/sentry-ruby/lib/sentry/std_lib_logger.rb b/sentry-ruby/lib/sentry/std_lib_logger.rb new file mode 100644 index 000000000..cee197e48 --- /dev/null +++ b/sentry-ruby/lib/sentry/std_lib_logger.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Sentry + # Ruby Logger support Add commentMore actions + # intercepts any logger instance and send the log to Sentry too. + module StdLibLogger + SEVERITY_MAP = { + 0 => :debug, + 1 => :info, + 2 => :warn, + 3 => :error, + 4 => :fatal + }.freeze + + def add(severity, message = nil, progname = nil, &block) + super + + return unless Sentry.initialized? && Sentry.get_current_hub + + # exclude sentry SDK logs -- to prevent recursive log action, + # do not process internal logs again + if message.nil? && progname != Sentry::Logger::PROGNAME + + # handle different nature of Ruby Logger class: + # inspo from Sentry::Breadcrumb::SentryLogger + if block_given? + message = yield + else + message = progname + end + + message = message.to_s.strip + + if !message.nil? && message != Sentry::Logger::PROGNAME && method = SEVERITY_MAP[severity] + Sentry.logger.send(method, message) + end + end + + super + end + end +end + +Sentry.register_patch(:logger) do |config| + if config.enable_logs + ::Logger.prepend(Sentry::StdLibLogger) + else + Sentry.sdk_logger.warn(":logger patch enabled but `enable_logs` is turned off - skipping applying patch") + end +end diff --git a/sentry-ruby/spec/sentry/std_lib_logger_spec.rb b/sentry-ruby/spec/sentry/std_lib_logger_spec.rb new file mode 100644 index 000000000..81ed66738 --- /dev/null +++ b/sentry-ruby/spec/sentry/std_lib_logger_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +RSpec.describe Sentry::StdLibLogger do + let(:logger) { ::Logger.new(IO::NULL) } + + context "when enable_logs is set to true but logger patch is not enabled" do + before do + perform_basic_setup do |config| + config.enable_logs = true + end + end + + it "does not send log using stdlib logger" do + logger.send(:info, "Hello World") + + expect(sentry_logs).to be_empty + end + end + + context "when enable_logs is set to true and logger patch is set" do + before do + perform_basic_setup do |config| + config.max_log_events = 1 + config.enable_logs = true + config.enabled_patches = [:redis, :puma, :http, :logger] + end + end + + ["info", "warn", "error", "fatal"].each do |level| + describe "##{level}" do + it "send logs using stdlib logger" do + logger.send(level, "Hello World") + + expect(sentry_logs).to_not be_empty + + log_event = sentry_logs.last + + expect(log_event[:level]).to eql(level) + expect(log_event[:body]).to eql("Hello World") + end + end + end + end +end