From 423ab2f0ee8c75286bf952153179f7ee66e03b5e Mon Sep 17 00:00:00 2001 From: Nathan Anderson Date: Fri, 27 Aug 2021 14:53:07 -0400 Subject: [PATCH 1/6] Add a with_tags method. Block Usage: Rackstash.with_tags(:foo) { Rails.logger.info "Hello" } Set-and-forget Usage: Rackstash.with_tags(:foo) Rails.logger.info "Hello" --- lib/rackstash.rb | 16 ++++++++++++++++ lib/rackstash/version.rb | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/rackstash.rb b/lib/rackstash.rb index ccd9e96..006925a 100644 --- a/lib/rackstash.rb +++ b/lib/rackstash.rb @@ -63,6 +63,22 @@ def self.tags=(tags) end self.tags = [] + def self.with_tags(*tags) + if block_given? + begin + original_tags = self.tags + with_log_buffer do + self.tags = self.tags + tags.map(&:to_s) + yield + end + ensure + self.tags = original_tags + end + else + self.tags = self.tags + tags.map(&:to_s) + end + end + def self.with_log_buffer(&block) if Rackstash.logger.respond_to?(:with_buffer) Rackstash.logger.with_buffer(&block) diff --git a/lib/rackstash/version.rb b/lib/rackstash/version.rb index 98f3034..2ab7569 100644 --- a/lib/rackstash/version.rb +++ b/lib/rackstash/version.rb @@ -1,3 +1,3 @@ module Rackstash - VERSION = "0.1.0" + VERSION = "0.2.0" end From dfda1c877cd677bc7b01d5576f1391c436aaa3ae Mon Sep 17 00:00:00 2001 From: Jeffrey Hardy Date: Fri, 3 Sep 2021 14:37:11 -0400 Subject: [PATCH 2/6] Introduce request_tags to capture tags from the current request `Rackstash.request_tags=` accepts an Array of callable objects or strings. Callable objects will be called with the current request. Usage: config.rackstash.request_tags = [ lambda { |request| request.subdomains.first || "no-account" }, lambda { |request| case when request.subdomains.first == "37smonitoring" "monitoring" when request.path.starts_with?("/queenbee") "queenbee" else "web" end } ] --- lib/rackstash.rb | 33 ++++++++++++++------ lib/rackstash/framework/base.rb | 3 ++ lib/rackstash/log_subscriber.rb | 7 +++++ lib/rackstash/rails_ext/action_controller.rb | 3 ++ lib/rackstash/version.rb | 2 +- 5 files changed, 37 insertions(+), 11 deletions(-) diff --git a/lib/rackstash.rb b/lib/rackstash.rb index 006925a..26d0d20 100644 --- a/lib/rackstash.rb +++ b/lib/rackstash.rb @@ -19,12 +19,12 @@ module Rackstash # # Currently supported formats are: # - Hash - # - Any object that responds to to_proc and returns a hash + # - Any object that responds to #call and returns a hash # mattr_writer :request_fields self.request_fields = HashWithIndifferentAccess.new def self.request_fields(controller) - if @@request_fields.respond_to?(:to_proc) + if @@request_fields.respond_to?(:call) ret = controller.instance_eval(&@@request_fields) else ret = @@request_fields @@ -37,13 +37,13 @@ def self.request_fields(controller) # # Currently supported formats are: # - Hash - # - Any object that responds to to_proc and returns a hash + # - Any object that responds to #call and returns a hash # mattr_writer :fields self.fields = HashWithIndifferentAccess.new def self.fields - if @@fields.respond_to?(:to_proc) - ret = @@fields.to_proc.call + if @@fields.respond_to?(:call) + ret = @@fields.call else ret = @@fields end @@ -59,23 +59,36 @@ def self.fields # Additonal tags which are attached to each buffered log event mattr_reader :tags def self.tags=(tags) - @@tags = tags.map(&:to_s) + @@tags = tags.map(&:to_s).uniq end self.tags = [] - def self.with_tags(*tags) + # Additional tags to be included when processing a request. + mattr_writer :request_tags + self.request_tags = [] + def self.request_tags(controller) + @@request_tags.map do |request_tag| + if request_tag.respond_to?(:call) + request_tag.call(controller.request) + else + request_tag + end + end + end + + def self.tagged(*tags, &block) if block_given? + original_tags = self.tags begin - original_tags = self.tags with_log_buffer do - self.tags = self.tags + tags.map(&:to_s) + self.tags += tags yield end ensure self.tags = original_tags end else - self.tags = self.tags + tags.map(&:to_s) + self.tags += tags end end diff --git a/lib/rackstash/framework/base.rb b/lib/rackstash/framework/base.rb index e984efe..6953bd3 100644 --- a/lib/rackstash/framework/base.rb +++ b/lib/rackstash/framework/base.rb @@ -4,9 +4,12 @@ module Base def setup(config={}) Rackstash.request_fields = config.rackstash[:request_fields] Rackstash.fields = config.rackstash[:fields] || HashWithIndifferentAccess.new + Rackstash.source = config.rackstash[:source] Rackstash.log_level = config.rackstash[:log_level] || :info + Rackstash.tags = config.rackstash[:tags] || [] + Rackstash.request_tags = config.rackstash[:request_tags] || [] end end end diff --git a/lib/rackstash/log_subscriber.rb b/lib/rackstash/log_subscriber.rb index d5ba115..58538f3 100644 --- a/lib/rackstash/log_subscriber.rb +++ b/lib/rackstash/log_subscriber.rb @@ -14,6 +14,8 @@ def process_action(event) Rails.logger.fields.reverse_merge!(data) Rails.logger.fields.merge! request_fields(payload) + + Rails.logger.tags.push *request_tags(payload) end def redirect_to(event) @@ -98,6 +100,10 @@ def location(event) end end + def request_tags(payload) + payload[:rackstash_request_tags] || [] + end + def request_fields(payload) payload[:rackstash_request_fields] || {} end @@ -108,6 +114,7 @@ module Instrumentation def append_info_to_payload(payload) super + payload[:rackstash_request_tags] = Rackstash.request_tags(self) payload[:rackstash_request_fields] = Rackstash.request_fields(self) end end diff --git a/lib/rackstash/rails_ext/action_controller.rb b/lib/rackstash/rails_ext/action_controller.rb index 7456b88..2346dff 100644 --- a/lib/rackstash/rails_ext/action_controller.rb +++ b/lib/rackstash/rails_ext/action_controller.rb @@ -84,6 +84,9 @@ def perform_action_with_rackstash request_fields = Rackstash.request_fields(self) logger.fields.merge!(request_fields) if request_fields + + request_tags = Rackstash.request_tags(self) + logger.tags.push *request_tags end end diff --git a/lib/rackstash/version.rb b/lib/rackstash/version.rb index 2ab7569..4619e2d 100644 --- a/lib/rackstash/version.rb +++ b/lib/rackstash/version.rb @@ -1,3 +1,3 @@ module Rackstash - VERSION = "0.2.0" + VERSION = "0.2.1" end From 230c1213c21b33912fe980e1fcdbebb255ae43d0 Mon Sep 17 00:00:00 2001 From: Jeffrey Hardy Date: Tue, 14 Sep 2021 17:00:59 -0400 Subject: [PATCH 3/6] Call request_fields with the current request instead of evaluating in the controller context --- README.md | 15 +++++++-------- lib/rackstash.rb | 18 ++++++------------ lib/rackstash/version.rb | 2 +- test/rackstash_test.rb | 18 +++++++----------- 4 files changed, 21 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index b8f193e..24feb40 100644 --- a/README.md +++ b/README.md @@ -102,23 +102,22 @@ config.rackstash.tags = ['ruby', 'rails2'] # Additional fields which are included into each log event that # originates from a captured request. -# Can either be a Hash or an object which responds to to_proc which -# subsequently returns a Hash. If it is the latter, the proc will be exceuted -# similar to an after filter in every request of the controller and thus has -# access to the controller state after the request was handled. -config.rackstash.request_fields = lambda do |controller| +# Can either be a Hash or a callable object which responds to #call and which +# subsequently returns a Hash. If it is the latter, the object will called +# with the `request` object after the request is handled. +config.rackstash.request_fields = lambda { |request| { :host => request.host, :source_ip => request.remote_ip, :user_agent => request.user_agent } -end +} # Additional fields that are to be included into every emitted log, both # buffered and not. You can use this to add global state information to the # log, e.g. from the current thread or from the current environment. -# Similar to the request_fields, this can be either a static Hash or an -# object which responds to to_proc and returns a Hash there. +# Similar to the request_fields, this can be either a static Hash or a +# callable object which responds to #call and returns a Hash. # # Note that the proc is not executed in a controller instance and thus doesn't # directly have access to the controller state. diff --git a/lib/rackstash.rb b/lib/rackstash.rb index 26d0d20..e634a2d 100644 --- a/lib/rackstash.rb +++ b/lib/rackstash.rb @@ -24,12 +24,9 @@ module Rackstash mattr_writer :request_fields self.request_fields = HashWithIndifferentAccess.new def self.request_fields(controller) - if @@request_fields.respond_to?(:call) - ret = controller.instance_eval(&@@request_fields) - else - ret = @@request_fields - end - HashWithIndifferentAccess.new(ret) + fields = @@request_fields + fields = fields.call(controller.request) if fields.respond_to?(:call) + HashWithIndifferentAccess.new(fields) end # Custom fields that will be merged with every log object, be it a captured @@ -42,12 +39,9 @@ def self.request_fields(controller) mattr_writer :fields self.fields = HashWithIndifferentAccess.new def self.fields - if @@fields.respond_to?(:call) - ret = @@fields.call - else - ret = @@fields - end - HashWithIndifferentAccess.new(ret) + fields = @@fields + fields = fields.call if fields.respond_to?(:call) + HashWithIndifferentAccess.new(fields) end # The source attribute in the generated Logstash output diff --git a/lib/rackstash/version.rb b/lib/rackstash/version.rb index 4619e2d..f00090c 100644 --- a/lib/rackstash/version.rb +++ b/lib/rackstash/version.rb @@ -1,3 +1,3 @@ module Rackstash - VERSION = "0.2.1" + VERSION = "0.3.0" end diff --git a/test/rackstash_test.rb b/test/rackstash_test.rb index 477f425..0eff8f8 100644 --- a/test/rackstash_test.rb +++ b/test/rackstash_test.rb @@ -50,9 +50,7 @@ def json end let(:controller) do - controller = Class.new(Object){attr_accessor :status}.new - controller.status = "running" - controller + Struct.new(:request).new(Struct.new(:status).new(200)) end it "won't be included in unbuffered mode" do @@ -72,31 +70,29 @@ def json end it "can be defined as a proc" do - Rackstash.request_fields = proc do |controller| + Rackstash.request_fields = proc do |request| { :foo => :bar, - :status => @status, - :instance_status => controller.status + :status => request.status } end Rackstash.request_fields(controller).must_be_instance_of HashWithIndifferentAccess - Rackstash.request_fields(controller).must_equal({"foo" => :bar, "status" => "running", "instance_status" => "running"}) + Rackstash.request_fields(controller).must_equal({"foo" => :bar, "status" => 200}) # TODO: fake a real request and ensure that the field gets set in the log output end it "can be defined as a lambda" do - Rackstash.request_fields = lambda do |controller| + Rackstash.request_fields = lambda do |request| { :foo => :bar, - :status => @status, - :instance_status => controller.status + :status => request.status } end Rackstash.request_fields(controller).must_be_instance_of HashWithIndifferentAccess - Rackstash.request_fields(controller).must_equal({"foo" => :bar, "status" => "running", "instance_status" => "running"}) + Rackstash.request_fields(controller).must_equal({"foo" => :bar, "status" => 200}) # TODO: fake a real request and ensure that the field gets set in the log output end From 08c6aa3d70443b7d4a23e9f3b2349bec9f5df035 Mon Sep 17 00:00:00 2001 From: Nathan Anderson Date: Tue, 31 Aug 2021 09:19:09 -0400 Subject: [PATCH 4/6] Gate usage of config.exceptions_app for rails 3.2+ --- lib/rackstash/framework/rails3.rb | 12 ++++++++---- lib/rackstash/version.rb | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/rackstash/framework/rails3.rb b/lib/rackstash/framework/rails3.rb index ced4e3f..dfcf7a8 100644 --- a/lib/rackstash/framework/rails3.rb +++ b/lib/rackstash/framework/rails3.rb @@ -31,10 +31,14 @@ def setup(config={}) # ActionDispatch captures exceptions too early for us to catch # Thus, we inject our own exceptions_app to be able to catch the # actual backtrace and add it to the fields - exceptions_app = config.exceptions_app || ActionDispatch::PublicExceptions.new(Rails.public_path) - config.exceptions_app = lambda do |env| - log_subscriber._extract_exception_backtrace(env) - exceptions_app.call(env) + if config.respond_to?(:exceptions_app) + exceptions_app = config.exceptions_app || ActionDispatch::PublicExceptions.new(Rails.public_path) + config.exceptions_app = lambda do |env| + log_subscriber._extract_exception_backtrace(env) + exceptions_app.call(env) + end + else + # TODO: figure out how to get exceptions in rails 3.0-3.1 end ActionController::Base.send :include, Rackstash::Instrumentation diff --git a/lib/rackstash/version.rb b/lib/rackstash/version.rb index f00090c..b9fedf0 100644 --- a/lib/rackstash/version.rb +++ b/lib/rackstash/version.rb @@ -1,3 +1,3 @@ module Rackstash - VERSION = "0.3.0" + VERSION = "0.3.0.basecamp" end From e271df49e8a910ded17ac63f1d5e7c8f9fdf83d5 Mon Sep 17 00:00:00 2001 From: Jeffrey Hardy Date: Mon, 8 Nov 2021 16:09:49 -0500 Subject: [PATCH 5/6] Expose the #tagged method on BufferedLogger so it can be used through the logger instance --- lib/rackstash/buffered_logger.rb | 4 ++++ test/buffered_logger_test.rb | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/lib/rackstash/buffered_logger.rb b/lib/rackstash/buffered_logger.rb index 737be54..f6898d7 100644 --- a/lib/rackstash/buffered_logger.rb +++ b/lib/rackstash/buffered_logger.rb @@ -113,6 +113,10 @@ def tags buffer && buffer[:tags] end + def tagged(*tags) + Rackstash.tagged(*tags) { yield } + end + def source=(value) @source = value @source_is_customized = true diff --git a/test/buffered_logger_test.rb b/test/buffered_logger_test.rb index 6c93346..de52270 100644 --- a/test/buffered_logger_test.rb +++ b/test/buffered_logger_test.rb @@ -139,6 +139,14 @@ def json json["@message"].must_equal " [INFO] Hello" end + it "can set additional tags for the duration of a block" do + subject.tagged("foo", "bar") { subject.info "Testing" } + json["@tags"].must_equal ["foo", "bar"] + + subject.info "Testing" + json["@tags"].must_equal [] + end + it "can set additional fields" do subject.with_buffer do subject.fields[:foo] = :bar From 511c900748d9ef947938d5b69bb1f339093f8a7f Mon Sep 17 00:00:00 2001 From: Jeffrey Hardy Date: Tue, 9 Nov 2021 16:56:26 -0500 Subject: [PATCH 6/6] Bump version to 0.3.1 --- lib/rackstash/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rackstash/version.rb b/lib/rackstash/version.rb index b9fedf0..137682c 100644 --- a/lib/rackstash/version.rb +++ b/lib/rackstash/version.rb @@ -1,3 +1,3 @@ module Rackstash - VERSION = "0.3.0.basecamp" + VERSION = "0.3.1.basecamp" end