lumberjack_rails 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Railtie for integrating Lumberjack::Logger with Rails applications.
4
+ #
5
+ # This railtie replaces the standard Rails logger with a Lumberjack::Logger while
6
+ # maintaining compatibility with Rails' logging configuration options.
7
+ #
8
+ # Configuration options:
9
+ # config.lumberjack.enabled (default: true)
10
+ # Whether to replace Rails.logger with Lumberjack::Logger
11
+ #
12
+ # config.lumberjack.device (default: Rails log file)
13
+ # The device to write logs to (file path, IO object, Lumberjack Device)
14
+ #
15
+ # config.lumberjack.level (default: config.log_level)
16
+ # The log level for the Lumberjack logger
17
+ #
18
+ # config.lumberjack.attributes (default: nil)
19
+ # Attributes to apply to log messages
20
+ #
21
+ # config.lumberjack.shift_age (default: 0)
22
+ # The age (in seconds) of log files before they are rotated or
23
+ # a shift name (daily, weekly, monthly)
24
+ #
25
+ # config.lumberjack.shift_size (default: 1048576)
26
+ # The size (in bytes) of log files before they are rotated if shift_age
27
+ # is set to 0.
28
+ #
29
+ # config.lumberjack.log_rake_tasks (default: false)
30
+ # Whether to redirect $stdout and $stderr to Rails.logger for rake tasks
31
+ # that depend on the :environment task when using a Lumberjack::Logger
32
+ #
33
+ # config.lumberjack.middleware (default: true)
34
+ # Whether to install Rack middleware that adds a Lumberjack context to each request.
35
+ #
36
+ # config.lumberjack.request_attributes_proc (default: nil)
37
+ # A proc to add tags to log entries for each request. The proc, will be
38
+ # called with the request object and must return a hash of attributes to
39
+ # include in each log entry for the request.
40
+ #
41
+ # config.lumberjack.silence_rack_request_started (default: false)
42
+ # Whether to silence the "Started ..." log lines in Rack::Logger. You may want to silence
43
+ # this entry if it is just creating noise in your production logs.
44
+ #
45
+ # config.lumberjack.*
46
+ # All other options are sent as options to the Lumberjack logger
47
+ # constructor.
48
+ #
49
+ # Example usage in config/application.rb:
50
+ # config.log_level = :info
51
+ # config.lumberjack.attributes = {app: "my_app", host: Lumberjack::Utils.hostname}
52
+ # config.lumberjack.device = STDOUT # optional override
53
+ class Lumberjack::Rails::Railtie < ::Rails::Railtie
54
+ class << self
55
+ # Create a Lumberjack logger based on Rails configuration.
56
+ #
57
+ # @param config [Rails::Application::Configuration] the Rails application configuration
58
+ # @param log_file_path [String, nil] optional path to the log file
59
+ # @return [Lumberjack::Logger, nil] the configured logger or nil if not enabled
60
+ def lumberjack_logger(config, log_file_path = nil)
61
+ return nil if config.logger
62
+ return nil if config.lumberjack.nil? || config.lumberjack == false
63
+ return nil unless config.lumberjack.enabled
64
+
65
+ # Determine the log device
66
+ device = config.lumberjack.device
67
+ if device.nil?
68
+ if log_file_path
69
+ FileUtils.mkdir_p(File.dirname(log_file_path)) unless File.exist?(File.dirname(log_file_path))
70
+ device = log_file_path
71
+ else
72
+ device = $stdout
73
+ end
74
+ end
75
+
76
+ # Determine the log level
77
+ level = config.lumberjack.level || config.log_level || :debug
78
+
79
+ # Set default attributes
80
+ attributes = config.lumberjack.attributes
81
+ if config.log_tags
82
+ attributes ||= {}
83
+ attributes["tags"] = config.log_tags
84
+ end
85
+
86
+ shift_age = config.lumberjack.shift_age || 0
87
+ shift_size = config.lumberjack.shift_size || 1048576
88
+
89
+ # Create logger options
90
+ logger_options = config.lumberjack.to_h.except(
91
+ :enabled,
92
+ :raise_logger_errors,
93
+ :device, :level,
94
+ :progname,
95
+ :attributes,
96
+ :shift_age,
97
+ :shift_size,
98
+ :log_rake_tasks,
99
+ :middleware,
100
+ :request_attribute,
101
+ :silence_rack_request_started
102
+ )
103
+
104
+ logger_options.merge!(
105
+ level: level,
106
+ formatter: config.lumberjack.formatter,
107
+ progname: config.lumberjack.progname
108
+ )
109
+
110
+ # Create the Lumberjack logger
111
+ logger = Lumberjack::Logger.new(device, shift_age, shift_size, **logger_options)
112
+ logger.tag!(attributes) if attributes
113
+ logger.formatter.prepend(Lumberjack::Rails.active_record_entry_formatter)
114
+
115
+ logger
116
+ end
117
+
118
+ # Redirect standard streams ($stdout, $stderr) to logger instances.
119
+ #
120
+ # @param config [Rails::Application::Configuration] the Rails application configuration
121
+ # @param logger [Lumberjack::Logger] the logger to redirect streams to
122
+ # @return [void]
123
+ def set_standard_streams_to_loggers!(config, logger)
124
+ return unless config.lumberjack&.log_rake_tasks
125
+ return unless logger.respond_to?(:fork) && logger.respond_to?(:puts)
126
+
127
+ if !$stdout.tty? && !$stdout.is_a?(::Logger)
128
+ stdout_logger = logger.fork
129
+ stdout_logger.default_severity = :info
130
+ $stdout = stdout_logger
131
+ end
132
+
133
+ if !$stderr.tty? && !$stderr.is_a?(::Logger)
134
+ stderr_logger = logger.fork
135
+ stderr_logger.default_severity = :warn
136
+ $stderr = stderr_logger
137
+ end
138
+ end
139
+ end
140
+
141
+ config.lumberjack = ActiveSupport::OrderedOptions.new
142
+ config.lumberjack.enabled = true
143
+ config.lumberjack.log_rake_tasks = false
144
+ config.lumberjack.template = "[{{time}} {{severity(padded)}} {{progname}} ({{pid}})] {{tags}} {{message}} -- {{attributes}}"
145
+ config.lumberjack.raise_logger_errors = !(Rails.env.development? || Rails.env.test?)
146
+
147
+ initializer "lumberjack.configure_logger", before: :initialize_logger do |app|
148
+ Lumberjack.raise_logger_errors = app.config.lumberjack.raise_logger_errors
149
+ Lumberjack::Rails.silence_rack_request_started = app.config.lumberjack.silence_rack_request_started
150
+
151
+ logger = Lumberjack::Rails::Railtie.lumberjack_logger(app.config, app.paths["log"]&.first)
152
+ app.config.logger = logger if logger
153
+ end
154
+
155
+ initializer "lumberjack.insert_middleware" do |app|
156
+ next unless app.config.lumberjack&.enabled
157
+
158
+ app.middleware.unshift(Lumberjack::Rails::ContextMiddleware)
159
+
160
+ if app.config.lumberjack.request_attributes_proc
161
+ app.middleware.use(Lumberjack::Rails::RequestAttributesMiddleware, app.config.lumberjack.request_attributes_proc)
162
+ end
163
+ end
164
+
165
+ config.after_initialize do
166
+ # Enhance the :environment task to set standard streams to loggers
167
+ # This will apply to any rake task that depends on :environment
168
+ if defined?(Rake::Task) && Rake::Task.task_defined?(:environment)
169
+ Rake::Task[:environment].enhance do
170
+ Lumberjack::Rails::Railtie.set_standard_streams_to_loggers!(::Rails.application.config, ::Rails.logger)
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lumberjack
4
+ module Rails
5
+ # This Rack middleware provides a hook for adding attributes from the request
6
+ # onto the Rails.logger context so that they will appear on all log entries
7
+ # for the request.
8
+ class RequestAttributesMiddleware
9
+ # @param app [#call] The Rack application.
10
+ # @param attributes_block [Proc] A block that takes the Rack request and returns
11
+ # a hash of attributes to add to the logger context for the request.
12
+ # The block will be called with an ActionDispatch::Request object.
13
+ def initialize(app, attributes_block)
14
+ unless attributes_block.respond_to?(:call)
15
+ raise ArgumentError.new("attributes_block must be a Proc or callable object")
16
+ end
17
+
18
+ @app = app
19
+ @attributes_block = attributes_block
20
+ end
21
+
22
+ # Process a request through the middleware stack with Lumberjack context.
23
+ #
24
+ # @param env [Hash] the Rack environment hash
25
+ # @return [Array] the Rack response array
26
+ def call(env)
27
+ return @app.call(env) if ::Rails.logger.nil?
28
+
29
+ Lumberjack::Rails.logger_context do
30
+ attributes = @attributes_block.call(ActionDispatch::Request.new(env))
31
+ if attributes.is_a?(Hash)
32
+ ::Rails.logger.tag(attributes)
33
+ elsif !attributes.nil?
34
+ warn "RequestAttributesMiddleware attributes_block did not return a Hash, got #{attributes.class.name}"
35
+ end
36
+
37
+ @app.call(env)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lumberjack
4
+ module Rails
5
+ # Extension for Lumberjack::ForkedLogger to support ActiveSupport tagged logging.
6
+ #
7
+ # This module adds tagged logging capabilities to forked loggers by
8
+ # delegating tagged calls to the parent logger when available.
9
+ module TaggedForkedLogger
10
+ # Execute a block with the specified tags if the parent logger supports tagging.
11
+ #
12
+ # @param tags [Array] the tags to apply during block execution
13
+ # @yield the block to execute with the specified tags
14
+ # @return [Object] the result of the block execution, or nil if parent doesn't support tagging
15
+ def tagged(*tags, &block)
16
+ if parent_logger.respond_to?(:tagged)
17
+ parent_logger.tagged(*tags, &block)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lumberjack::Rails
4
+ # Extension for the Lumberjack::EntryFormatter that adds support for adding the array of
5
+ # tags added by ActiveSupport::TaggedLogging.
6
+ #
7
+ # This module integrates ActiveSupport's tagged logging mechanism with Lumberjack's
8
+ # entry formatting, ensuring that tags from Rails' tagged logging are properly
9
+ # included in the formatted log output.
10
+ module TaggedLoggingFormatter
11
+ # Format a log message with support for ActiveSupport tagged logging.
12
+ #
13
+ # @param message [String] the log message to format
14
+ # @param tags [Hash, nil] existing tags to include in the formatted output
15
+ # @return [String] the formatted log message
16
+ def format(message, tags)
17
+ tagged_values = current_tags if respond_to?(:current_tags)
18
+ if tagged_values && !tagged_values.empty?
19
+ tagged = {"tags" => tagged_values}
20
+ new_tags = tags.nil? ? tagged : tags.merge(tagged)
21
+ else
22
+ new_tags = tags
23
+ end
24
+
25
+ super(message, new_tags)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lumberjack"
4
+ require "active_support"
5
+
6
+ # Lumberjack is a logging framework for Ruby applications.
7
+ # This gem extends Lumberjack with Rails-specific functionality.
8
+ module Lumberjack
9
+ # Rails integration for Lumberjack logger.
10
+ #
11
+ # This module provides integration between Lumberjack and Rails applications,
12
+ # enhancing Rails' logging capabilities while maintaining compatibility with
13
+ # existing Rails logging patterns.
14
+ module Rails
15
+ VERSION = ::File.read(::File.join(__dir__, "..", "..", "VERSION")).strip.freeze
16
+
17
+ @silence_rack_request_started = false
18
+ @silenced_log_events = Set.new
19
+
20
+ class << self
21
+ # Safely wrap Rails.logger with a Lumberjack context.
22
+ #
23
+ # @param additional_logger [Logger] an optional additional logger to wrap with a context.
24
+ # @yield [Logger] the block to execute with the wrapped logger context.
25
+ # @return [Object] the result of the block execution.
26
+ def logger_context(additional_logger = nil, &block)
27
+ rails_logger = ::Rails.logger
28
+ Lumberjack.context do
29
+ if additional_logger && rails_logger != additional_logger
30
+ wrap_block_with_logger_context(rails_logger) do
31
+ wrap_block_with_logger_context(additional_logger, &block)
32
+ end
33
+ else
34
+ wrap_block_with_logger_context(rails_logger, &block)
35
+ end
36
+ end
37
+ end
38
+
39
+ # Configuration option to silence "Started ..." log lines in Rack::Logger.
40
+ #
41
+ # When set to true, the "Started ..." log lines generated by Rack::Logger
42
+ # will be suppressed. This can help reduce log noise in applications where
43
+ # these lines are not needed.
44
+ #
45
+ # @param value [Boolean] whether to silence "Started ..." log lines (default: false)
46
+ # @return [void]
47
+ def silence_rack_request_started=(value)
48
+ @silence_rack_request_started = !!value
49
+ end
50
+
51
+ # Returns true if the "Started ..." log lines in Rack::Logger are silenced.
52
+ #
53
+ # @return [Boolean] whether to silence "Started ..." log lines (default: false)
54
+ def silence_rack_request_started?
55
+ @silence_rack_request_started
56
+ end
57
+
58
+ # EntryFormatter that adds a formatter for ActiveRecord models that outputs
59
+ # only the type and id.
60
+ #
61
+ # @return [Lumberjack::EntryFormatter] the configured entry formatter
62
+ def active_record_entry_formatter
63
+ Lumberjack::EntryFormatter.build do |formatter|
64
+ formatter.format_message("ActiveRecord::Base") { |record| "#{record.class.name}.#{record.id || "new_record"}" }
65
+ formatter.format_attributes("ActiveRecord::Base", :id)
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ # Wrap a block with a logger context if the logger supports it.
72
+ #
73
+ # @param logger [Logger] the logger to wrap
74
+ # @yield the block to execute within the logger context
75
+ # @return [Object] the result of the block execution
76
+ def wrap_block_with_logger_context(logger, &block)
77
+ if logger&.respond_to?(:context)
78
+ logger.context(&block)
79
+ else
80
+ block.call
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ require_relative "rails/action_cable_extension"
88
+ require_relative "rails/action_controller_extension"
89
+ require_relative "rails/action_controller_log_subscriber_extension"
90
+ require_relative "rails/action_mailbox_extension"
91
+ require_relative "rails/action_mailer_extension"
92
+ require_relative "rails/active_job_extension"
93
+ require_relative "rails/broadcast_logger_extension"
94
+ require_relative "rails/context_middleware"
95
+ require_relative "rails/log_at_level"
96
+ require_relative "rails/log_subscriber_extension"
97
+ require_relative "rails/rack_logger_extension"
98
+ require_relative "rails/request_attributes_middleware"
99
+ require_relative "rails/tagged_forked_logger"
100
+ require_relative "rails/tagged_logging_formatter"
101
+
102
+ require_relative "rails/apply_patches"
103
+
104
+ if defined?(::Rails::Railtie)
105
+ require_relative "rails/railtie"
106
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lumberjack/rails"
@@ -0,0 +1,40 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "lumberjack_rails"
3
+ spec.version = File.read(File.join(__dir__, "VERSION")).strip
4
+ spec.authors = ["Brian Durand"]
5
+ spec.email = ["bbdurand@gmail.com"]
6
+
7
+ spec.summary = "Support for using the lumberjack logging library in Rails applications."
8
+ spec.homepage = "https://github.com/bdurand/lumberjack_rails"
9
+ spec.license = "MIT"
10
+
11
+ spec.metadata = {
12
+ "homepage_uri" => spec.homepage,
13
+ "source_code_uri" => spec.homepage,
14
+ "changelog_uri" => "#{spec.homepage}/blob/main/CHANGE_LOG.md"
15
+ }
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ ignore_files = %w[
20
+ .gitignore
21
+ .travis.yml
22
+ Appraisals
23
+ Gemfile
24
+ Gemfile.lock
25
+ Rakefile
26
+ gemfiles/
27
+ spec/
28
+ test_app/
29
+ ]
30
+ spec.files = Dir.chdir(__dir__) do
31
+ `git ls-files -z`.split("\x0").reject { |f| ignore_files.any? { |path| f.start_with?(path) } }
32
+ end
33
+
34
+ spec.require_paths = ["lib"]
35
+
36
+ spec.required_ruby_version = ">= 3.0"
37
+
38
+ spec.add_dependency "lumberjack", ">=2.0"
39
+ spec.add_dependency "activesupport", ">= 7.1"
40
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lumberjack_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Durand
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2025-10-20 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: lumberjack
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: activesupport
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '7.1'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '7.1'
40
+ email:
41
+ - bbdurand@gmail.com
42
+ executables: []
43
+ extensions: []
44
+ extra_rdoc_files: []
45
+ files:
46
+ - ".github/dependabot.yml"
47
+ - ".github/workflows/continuous_integration.yml"
48
+ - ".standard.yml"
49
+ - ".yardopts"
50
+ - CHANGE_LOG.md
51
+ - MIT_LICENSE.txt
52
+ - README.md
53
+ - VERSION
54
+ - lib/lumberjack/rails.rb
55
+ - lib/lumberjack/rails/action_cable_extension.rb
56
+ - lib/lumberjack/rails/action_controller_extension.rb
57
+ - lib/lumberjack/rails/action_controller_log_subscriber_extension.rb
58
+ - lib/lumberjack/rails/action_mailbox_extension.rb
59
+ - lib/lumberjack/rails/action_mailer_extension.rb
60
+ - lib/lumberjack/rails/active_job_extension.rb
61
+ - lib/lumberjack/rails/apply_patches.rb
62
+ - lib/lumberjack/rails/broadcast_logger_extension.rb
63
+ - lib/lumberjack/rails/context_middleware.rb
64
+ - lib/lumberjack/rails/log_at_level.rb
65
+ - lib/lumberjack/rails/log_subscriber_extension.rb
66
+ - lib/lumberjack/rails/rack_logger_extension.rb
67
+ - lib/lumberjack/rails/railtie.rb
68
+ - lib/lumberjack/rails/request_attributes_middleware.rb
69
+ - lib/lumberjack/rails/tagged_forked_logger.rb
70
+ - lib/lumberjack/rails/tagged_logging_formatter.rb
71
+ - lib/lumberjack_rails.rb
72
+ - lumberjack_rails.gemspec
73
+ homepage: https://github.com/bdurand/lumberjack_rails
74
+ licenses:
75
+ - MIT
76
+ metadata:
77
+ homepage_uri: https://github.com/bdurand/lumberjack_rails
78
+ source_code_uri: https://github.com/bdurand/lumberjack_rails
79
+ changelog_uri: https://github.com/bdurand/lumberjack_rails/blob/main/CHANGE_LOG.md
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '3.0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubygems_version: 3.6.2
95
+ specification_version: 4
96
+ summary: Support for using the lumberjack logging library in Rails applications.
97
+ test_files: []