Skip to content

Commit

Permalink
Feature/tagged logging (#1) (#2)
Browse files Browse the repository at this point in the history
* Add tagged logging support

Implement tagged logging similar to ActiveSupport::TaggedLogging.

* Use log_tags attribute on logger

Don't use the default_options to pass the tags into the logger.  This
causes the tags field to be sent over to graylog as an array.  Instead
pass the tag names into an attribute called log_tags that matches with
the Rails standard of config.log_tags.

* Replace Thread#[] with Thread#thread_variable_get/set

* Skip log tags tests for Ruby 1.9

* Fix CI for JRuby

Co-authored-by: Mark Glenn <[email protected]>
Co-authored-by: Marcus Ilgner <[email protected]>
Co-authored-by: Vladimir Kitaev <[email protected]>

Co-authored-by: Mark Glenn <[email protected]>
Co-authored-by: Marcus Ilgner <[email protected]>
Co-authored-by: Vladimir Kitaev <[email protected]>
  • Loading branch information
4 people authored Jul 31, 2020
1 parent eb2d31c commit d7f194c
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 6 deletions.
3 changes: 0 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,3 @@ DEPENDENCIES
rack (< 2.0)
shoulda (~> 2.11.3)
test-unit (~> 3.2.0)

BUNDLED WITH
1.14.6
36 changes: 33 additions & 3 deletions lib/gelf/logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module GELF
# Methods for compatibility with Ruby Logger.
module LoggerCompatibility

attr_accessor :formatter
attr_accessor :formatter, :log_tags

# Use it like Logger#add... or better not to use at all.
def add(level, message = nil, progname = nil, &block)
Expand All @@ -28,9 +28,14 @@ def add(level, message = nil, progname = nil, &block)
message_hash.merge!(self.class.extract_hash_from_exception(message))
end

if message_hash.key?('short_message') && !message_hash['short_message'].empty?
notify_with_level(level, message_hash)
return if !message_hash.key?('short_message') || message_hash['short_message'].empty?

# Include tags in message hash
Array(log_tags).each_with_index do |tag_name, index|
message_hash.merge!("_#{tag_name}" => current_tags[index]) if current_tags[index]
end

notify_with_level(level, message_hash)
end

# Redefines methods in +Notifier+.
Expand All @@ -51,12 +56,37 @@ def add(level, message = nil, progname = nil, &block)
def <<(message)
notify_with_level(GELF::UNKNOWN, 'short_message' => message)
end

def tagged(*tags)
new_tags = push_tags(*tags)
yield self
ensure
current_tags.pop(new_tags.size)
end

def push_tags(*tags)
tags.flatten.reject{ |t| t.respond_to?(:empty?) ? !!t.empty? : !t }.tap do |new_tags|
current_tags.concat new_tags
end
end

def current_tags
val = Thread.current.thread_variable_get(:gelf_tagged_logging_tags)
return val unless val.nil?
Thread.current.thread_variable_set(:gelf_tagged_logging_tags, [])
end
end

# Graylog2 notifier, compatible with Ruby Logger.
# You can use it with Rails like this:
# config.logger = GELF::Logger.new("localhost", 12201, "WAN", { :facility => "appname" })
# config.colorize_logging = false
#
# Tagged logging (with tags from rack middleware) (order of tags is important)
# Adds custom gelf messages: { '_uuid_name' => <uuid>, '_remote_ip_name' => <remote_ip> }
# config.logger = GELF::Logger.new("localhost", 12201, "LAN", { :facility => "appname" })
# config.log_tags = [:uuid, :remote_ip]
# config.logger.log_tags = [:uuid_name, :remote_ip_name] # Same order as config.log_tags
class Logger < Notifier
include LoggerCompatibility
end
Expand Down
36 changes: 36 additions & 0 deletions test/test_logger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,42 @@ class TestLogger < Test::Unit::TestCase
@logger.formatter
end

# Supports only Ruby 2.0 or higher
if RUBY_VERSION[0, 1].to_i >= 2
context "#tagged" do
# logger.tagged("TAG") { logger.info "Message" }
should "support tagged method" do
@logger.expects(:notify_with_level!).with do |level, hash|
level == GELF::INFO &&
hash['short_message'] == 'Message' &&
hash['facility'] == 'gelf-rb'
end

str = "TAG"
str.stubs(:blank?).returns(true)

@logger.tagged(str) { @logger.info "Message" }
end

should "set custom gelf message with tag name and tag content" do
# I want the first tag with name 'test_tag'
@logger.log_tags = [:test_tag]

@logger.expects(:notify_with_level!).with do |level, hash|
level == GELF::INFO &&
hash['short_message'] == 'Message' &&
hash['facility'] == 'gelf-rb' &&
hash['_test_tag'] == 'TAG' # TAG should be in the hash
end

str = "TAG"
str.stubs(:blank?).returns(false)

@logger.tagged(str) { @logger.info "Message" }
end
end
end

context "close" do
should "close socket" do
@sender.expects(:close).once
Expand Down

0 comments on commit d7f194c

Please sign in to comment.