Skip to content

Commit

Permalink
Add logger.push_tags and .pop_tags to complement logger.tagged
Browse files Browse the repository at this point in the history
Avoid memory leak from unflushed logs on other threads leaving tags behind.

Conflicts:
	activesupport/CHANGELOG.md
	activesupport/lib/active_support/tagged_logging.rb
	activesupport/test/tagged_logging_test.rb
  • Loading branch information
jeremy committed Sep 27, 2012
1 parent 032c2b6 commit 20f5f08
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 18 deletions.
14 changes: 14 additions & 0 deletions activesupport/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
## Rails 3.2.9 (unreleased)

* Add logger.push_tags and .pop_tags to complement logger.tagged:

class Job
def before
Rails.logger.push_tags :jobs, self.class.name
end

def after
Rails.logger.pop_tags 2
end
end

*Jeremy Kemper*

* Add %:z and %::z format string support to ActiveSupport::TimeWithZone#strftime. [fixes #6962] *kennyj*

## Rails 3.2.8 (Aug 9, 2012) ##
Expand Down
46 changes: 28 additions & 18 deletions activesupport/lib/active_support/tagged_logging.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,27 @@ module ActiveSupport
class TaggedLogging
def initialize(logger)
@logger = logger
@tags = Hash.new { |h,k| h[k] = [] }
end

def tagged(*new_tags)
tags = current_tags
new_tags = Array.wrap(new_tags).flatten.reject(&:blank?)
tags.concat new_tags
yield
def tagged(*tags)
new_tags = push_tags *tags
yield self
ensure
new_tags.size.times { tags.pop }
pop_tags new_tags.size
end

def push_tags(*tags)
tags.flatten.reject(&:blank?).tap do |new_tags|
current_tags.concat new_tags
end
end

def pop_tags(size = 1)
current_tags.pop size
end

def clear_tags!
current_tags.clear
end

def silence(temporary_level = Logger::ERROR, &block)
Expand All @@ -46,25 +57,24 @@ def #{severity}(progname = nil, &block)
end

def flush
@tags.delete(Thread.current)
clear_tags!
@logger.flush if @logger.respond_to?(:flush)
end

def method_missing(method, *args)
@logger.send(method, *args)
end

protected

def tags_text
tags = current_tags
if tags.any?
tags.collect { |tag| "[#{tag}]" }.join(" ") + " "
private
def tags_text
tags = current_tags
if tags.any?
tags.collect { |tag| "[#{tag}] " }.join
end
end
end

def current_tags
@tags[Thread.current]
def current_tags
Thread.current[:activesupport_tagged_logging_tags] ||= []
end
end
end
end
27 changes: 27 additions & 0 deletions activesupport/test/tagged_logging_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,33 @@ def flush(*)
assert_equal "[BCX] [Jason] [New] Funky time\n", @output.string
end

test "tagged are flattened" do
@logger.tagged("BCX", %w(Jason New)) { @logger.info "Funky time" }
assert_equal "[BCX] [Jason] [New] Funky time\n", @output.string
end

test "push and pop tags directly" do
assert_equal %w(A B C), @logger.push_tags('A', ['B', ' ', ['C']])
@logger.info 'a'
assert_equal %w(C), @logger.pop_tags
@logger.info 'b'
assert_equal %w(B), @logger.pop_tags(1)
@logger.info 'c'
assert_equal [], @logger.clear_tags!
@logger.info 'd'
assert_equal "[A] [B] [C] a\n[A] [B] b\n[A] c\nd\n", @output.string
end

test "does not strip message content" do
@logger.info " Hello"
assert_equal " Hello\n", @output.string
end

test "provides access to the logger instance" do
@logger.tagged("BCX") { |logger| logger.info "Funky time" }
assert_equal "[BCX] Funky time\n", @output.string
end

test "tagged once with blank and nil" do
@logger.tagged(nil, "", "New") { @logger.info "Funky time" }
assert_equal "[New] Funky time\n", @output.string
Expand Down

0 comments on commit 20f5f08

Please sign in to comment.