From 3ce36dc65b9eb862bd00875cefa9f39e2d7ae5d8 Mon Sep 17 00:00:00 2001 From: Holger Frohloff Date: Wed, 22 Mar 2023 09:14:25 +0000 Subject: [PATCH 1/3] Update Ruby to v2.7 and activesupport to v 7.0+ --- sensible_logging.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sensible_logging.gemspec b/sensible_logging.gemspec index 530d9ea..a143dd0 100644 --- a/sensible_logging.gemspec +++ b/sensible_logging.gemspec @@ -19,11 +19,11 @@ Gem::Specification.new do |spec| f.match(%r{^(test|spec|features)/}) end - spec.required_ruby_version = '>= 2.6' + spec.required_ruby_version = '>= 2.7' spec.require_paths = ['lib'] - spec.add_runtime_dependency 'activesupport', '>= 5.2', '< 7.0' + spec.add_runtime_dependency 'activesupport', '>= 7.0', '< 7.1' spec.add_runtime_dependency 'rack', '>= 2', '< 4' spec.add_development_dependency 'bundler' From 6b5548aa1230d555f7f9a5f03d4be5491fa36a87 Mon Sep 17 00:00:00 2001 From: Holger Frohloff Date: Wed, 22 Mar 2023 09:28:09 +0000 Subject: [PATCH 2/3] WIP require local tagged_logging class --- lib/active_support/tagged_logging.rb | 148 ++++++++++++++++++ .../middlewares/tagged_logger.rb | 2 +- 2 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 lib/active_support/tagged_logging.rb diff --git a/lib/active_support/tagged_logging.rb b/lib/active_support/tagged_logging.rb new file mode 100644 index 0000000..42e83e8 --- /dev/null +++ b/lib/active_support/tagged_logging.rb @@ -0,0 +1,148 @@ +# frozen_string_literal: true + +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/object/blank" +require "logger" +require "active_support/logger" +require "active_support/isolated_execution_state" + +module ActiveSupport + # Wraps any standard Logger object to provide tagging capabilities. + # + # May be called with a block: + # + # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)) + # logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff" + # logger.tagged('BCX', "Jason") { logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff" + # logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff" + # + # If called without a block, a new logger will be returned with applied tags: + # + # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)) + # logger.tagged("BCX").info "Stuff" # Logs "[BCX] Stuff" + # logger.tagged("BCX", "Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff" + # logger.tagged("BCX").tagged("Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff" + # + # This is used by the default Rails.logger as configured by Railties to make + # it easy to stamp log lines with subdomains, request ids, and anything else + # to aid debugging of multi-user production applications. + module TaggedLogging + module Formatter # :nodoc: + # This method is invoked when a log event occurs. + def call(severity, timestamp, progname, msg) + super(severity, timestamp, progname, tag_stack.format_message(msg)) + end + + def tagged(*tags) + pushed_count = tag_stack.push_tags(tags).size + yield self + ensure + pop_tags(pushed_count) + end + + def push_tags(*tags) + tag_stack.push_tags(tags) + end + + def pop_tags(count = 1) + tag_stack.pop_tags(count) + end + + def clear_tags! + tag_stack.clear + end + + def tag_stack + # We use our object ID here to avoid conflicting with other instances + @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}" + ::ActiveSupport::IsolatedExecutionState[@thread_key] ||= TagStack.new + end + + def current_tags + tag_stack.tags + end + + def tags_text + tag_stack.format_message("") + end + end + + class TagStack # :nodoc: + attr_reader :tags + + def initialize + @tags = [] + @tags_string = nil + end + + def push_tags(tags) + @tags_string = nil + tags.flatten! + tags.reject!(&:blank?) + @tags.concat(tags) + tags + end + + def pop_tags(count) + @tags_string = nil + @tags.pop(count) + end + + def clear + @tags_string = nil + @tags.clear + end + + def format_message(message) + if @tags.empty? + message + elsif @tags.size == 1 + "[#{@tags[0]}] #{message}" + else + @tags_string ||= "[#{@tags.join("] [")}] " + "#{@tags_string}#{message}" + end + end + end + + module LocalTagStorage # :nodoc: + attr_accessor :tag_stack + + def self.extended(base) + base.tag_stack = TagStack.new + end + end + + def self.new(logger) + logger = logger.clone + + if logger.formatter + logger.formatter = logger.formatter.clone + else + # Ensure we set a default formatter so we aren't extending nil! + logger.formatter = ActiveSupport::Logger::SimpleFormatter.new + end + + logger.formatter.extend Formatter + logger.extend(self) + end + + delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter + + def tagged(*tags) + if block_given? + formatter.tagged(*tags) { yield self } + else + logger = ActiveSupport::TaggedLogging.new(self) + logger.formatter.extend LocalTagStorage + logger.push_tags(*formatter.current_tags, *tags) + logger + end + end + + def flush + clear_tags! + super if defined?(super) + end + end +end diff --git a/lib/sensible_logging/middlewares/tagged_logger.rb b/lib/sensible_logging/middlewares/tagged_logger.rb index e6f8b89..559ed37 100644 --- a/lib/sensible_logging/middlewares/tagged_logger.rb +++ b/lib/sensible_logging/middlewares/tagged_logger.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'ipaddr' -require 'active_support/tagged_logging' +require_relative '../../active_support/tagged_logging' require_relative '../helpers/subdomain_parser' # Allow custom tags to be captured From 8a739dda291fff0f2e78988ac7c0616f9cf8df8e Mon Sep 17 00:00:00 2001 From: Holger Frohloff Date: Wed, 22 Mar 2023 14:34:19 +0000 Subject: [PATCH 3/3] Require complete active_support gem According to this comment [1] we need to load the whole of active_support and cannot load the tagged_logging class individually. [1] https://github.com/rails/rails/pull/47733#issuecomment-1479671957 --- lib/active_support/tagged_logging.rb | 148 ------------------ .../middlewares/tagged_logger.rb | 2 +- 2 files changed, 1 insertion(+), 149 deletions(-) delete mode 100644 lib/active_support/tagged_logging.rb diff --git a/lib/active_support/tagged_logging.rb b/lib/active_support/tagged_logging.rb deleted file mode 100644 index 42e83e8..0000000 --- a/lib/active_support/tagged_logging.rb +++ /dev/null @@ -1,148 +0,0 @@ -# frozen_string_literal: true - -require "active_support/core_ext/module/delegation" -require "active_support/core_ext/object/blank" -require "logger" -require "active_support/logger" -require "active_support/isolated_execution_state" - -module ActiveSupport - # Wraps any standard Logger object to provide tagging capabilities. - # - # May be called with a block: - # - # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)) - # logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff" - # logger.tagged('BCX', "Jason") { logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff" - # logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff" - # - # If called without a block, a new logger will be returned with applied tags: - # - # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)) - # logger.tagged("BCX").info "Stuff" # Logs "[BCX] Stuff" - # logger.tagged("BCX", "Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff" - # logger.tagged("BCX").tagged("Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff" - # - # This is used by the default Rails.logger as configured by Railties to make - # it easy to stamp log lines with subdomains, request ids, and anything else - # to aid debugging of multi-user production applications. - module TaggedLogging - module Formatter # :nodoc: - # This method is invoked when a log event occurs. - def call(severity, timestamp, progname, msg) - super(severity, timestamp, progname, tag_stack.format_message(msg)) - end - - def tagged(*tags) - pushed_count = tag_stack.push_tags(tags).size - yield self - ensure - pop_tags(pushed_count) - end - - def push_tags(*tags) - tag_stack.push_tags(tags) - end - - def pop_tags(count = 1) - tag_stack.pop_tags(count) - end - - def clear_tags! - tag_stack.clear - end - - def tag_stack - # We use our object ID here to avoid conflicting with other instances - @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}" - ::ActiveSupport::IsolatedExecutionState[@thread_key] ||= TagStack.new - end - - def current_tags - tag_stack.tags - end - - def tags_text - tag_stack.format_message("") - end - end - - class TagStack # :nodoc: - attr_reader :tags - - def initialize - @tags = [] - @tags_string = nil - end - - def push_tags(tags) - @tags_string = nil - tags.flatten! - tags.reject!(&:blank?) - @tags.concat(tags) - tags - end - - def pop_tags(count) - @tags_string = nil - @tags.pop(count) - end - - def clear - @tags_string = nil - @tags.clear - end - - def format_message(message) - if @tags.empty? - message - elsif @tags.size == 1 - "[#{@tags[0]}] #{message}" - else - @tags_string ||= "[#{@tags.join("] [")}] " - "#{@tags_string}#{message}" - end - end - end - - module LocalTagStorage # :nodoc: - attr_accessor :tag_stack - - def self.extended(base) - base.tag_stack = TagStack.new - end - end - - def self.new(logger) - logger = logger.clone - - if logger.formatter - logger.formatter = logger.formatter.clone - else - # Ensure we set a default formatter so we aren't extending nil! - logger.formatter = ActiveSupport::Logger::SimpleFormatter.new - end - - logger.formatter.extend Formatter - logger.extend(self) - end - - delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter - - def tagged(*tags) - if block_given? - formatter.tagged(*tags) { yield self } - else - logger = ActiveSupport::TaggedLogging.new(self) - logger.formatter.extend LocalTagStorage - logger.push_tags(*formatter.current_tags, *tags) - logger - end - end - - def flush - clear_tags! - super if defined?(super) - end - end -end diff --git a/lib/sensible_logging/middlewares/tagged_logger.rb b/lib/sensible_logging/middlewares/tagged_logger.rb index 559ed37..15fb9dc 100644 --- a/lib/sensible_logging/middlewares/tagged_logger.rb +++ b/lib/sensible_logging/middlewares/tagged_logger.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'ipaddr' -require_relative '../../active_support/tagged_logging' +require 'active_support' require_relative '../helpers/subdomain_parser' # Allow custom tags to be captured