Skip to content

Commit

Permalink
Ongoing work to getting the logger to a point where I am happy, this
Browse files Browse the repository at this point in the history
commit has been re-thinking how the logger does things like formatting
and reducing the object allocations that are required throughout the
logging pipeline.

I also introduced things like an LRU cache for templates, and did ALOT
of cleanup.
  • Loading branch information
stefansedich committed Oct 4, 2016
1 parent b4cd0eb commit a9aa9ae
Show file tree
Hide file tree
Showing 27 changed files with 308 additions and 230 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
/pkg/
/spec/reports/
/tmp/
/.tags
/.tags*
1 change: 0 additions & 1 deletion lib/semlogr.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
require 'semlogr/version'
require 'semlogr/log_configurator'
require 'semlogr/logger'
8 changes: 4 additions & 4 deletions lib/semlogr/events/log_event.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Semlogr
module Messages
module Events
class LogEvent
attr_reader :level
attr_reader :template
Expand All @@ -8,15 +8,15 @@ class LogEvent
attr_reader :timestamp

def initialize(level, template, error, properties)
@timestamp = Time.now.utc
@level = level
@template = template
@error = error
@properties = properties
@timestamp = DateTime.now
end

def render
@template.render(@properties)
def render(output)
@template.render(output, @properties)
end
end
end
Expand Down
39 changes: 39 additions & 0 deletions lib/semlogr/formatters/json_formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
require 'json'

module Semlogr
module Formatters
class JsonFormatter
def format(log_event)
entry = {
timestamp: log_event.timestamp,
level: log_event.level,
message: render_message(log_event)
}

if log_event.error
entry[:error] = {
type: log_event.error.class,
message: log_event.error.message,
backtrace: log_event.error.backtrace
}
end

if log_event.properties.any?
entry[:properties] = log_event.properties
end

"#{entry.to_json}\n"
end

private

def render_message(log_event)
output = String.new

log_event.render(output)

output
end
end
end
end
28 changes: 28 additions & 0 deletions lib/semlogr/formatters/property_value_formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Semlogr
module Formatters
class PropertyValueFormatter
QUOTE = "\""

def self.format(output, property_value)
return unless property_value

case property_value
when String
output << QUOTE
output << property_value
output << QUOTE
when StandardError
output << "#{property_value.class}: #{property_value.message}"

if property_value.backtrace
output << "\n\s\s#{property_value.backtrace.join("\n\s\s")}\n"
else
output << "\n"
end
else
output << property_value.to_s
end
end
end
end
end
37 changes: 37 additions & 0 deletions lib/semlogr/formatters/text_formatter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require 'semlogr/templates/parser'
require 'semlogr/properties/output_properties'
require 'semlogr/templates/property_token'

module Semlogr
module Formatters
class TextFormatter
DEFAULT_TEMPLATE = "[{timestamp}] {level}: {message}\n{error}"

def initialize(template: DEFAULT_TEMPLATE)
@template = Templates::Parser.parse(template)
end

def format(log_event)
output = String.new
properties = Properties::OutputProperties.create(log_event)

@template.tokens.each do |token|
case token
when Templates::PropertyToken
if token.property_name == :message
log_event.render(output)
else
next unless properties[token.property_name]

token.render(output, properties)
end
else
token.render(output, properties)
end
end

output
end
end
end
end
24 changes: 0 additions & 24 deletions lib/semlogr/log_configurator.rb

This file was deleted.

26 changes: 26 additions & 0 deletions lib/semlogr/log_level.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Semlogr
class LogLevel
include Comparable

attr_reader :level

def initialize(level, level_string)
@level = level
@level_string = level_string
end

def <=>(log_level)
@level <=> log_level.level
end

def to_s
@level_string
end

DEBUG = LogLevel.new(::Logger::DEBUG, 'DEBUG')
INFO = LogLevel.new(::Logger::INFO, 'INFO')
WARN = LogLevel.new(::Logger::WARN, 'WARN')
ERROR = LogLevel.new(::Logger::ERROR, 'ERROR')
FATAL = LogLevel.new(::Logger::FATAL, 'FATAL')
end
end
47 changes: 27 additions & 20 deletions lib/semlogr/logger.rb
Original file line number Diff line number Diff line change
@@ -1,46 +1,54 @@
require 'logger'
require 'semlogr/logger_configuration'
require 'semlogr/log_level'
require 'semlogr/events/log_event'
require 'semlogr/templates/parser'
require 'semlogr/properties/message_properties'

module Semlogr
class Logger
def debug?; @min_level <= ::Logger::DEBUG; end
def info?; @min_level <= ::Logger::INFO; end
def warn?; @min_level <= ::Logger::WARN; end
def error?; @min_level <= ::Logger::ERROR; end
def fatal?; @min_level <= ::Logger::FATAL; end

def initialize(min_level = ::Logger::DEBUG, sinks = [])
@min_level = min_level
@sinks = sinks
def debug?; @level <= LogLevel::DEBUG; end
def info?; @level <= LogLevel::INFO; end
def warn?; @level <= LogLevel::WARN; end
def error?; @level <= LogLevel::ERROR; end
def fatal?; @level <= LogLevel::FATAL; end

def initialize(config)
@level = config.level
@sinks = config.sinks
end

def self.create
config = LoggerConfiguration.new
yield(config)

Logger.new(config)
end

def debug(template = nil, error: nil, **properties, &block)
log(::Logger::DEBUG, template, error, properties, &block)
log(LogLevel::DEBUG, template, error, properties, &block)
end

def info(template = nil, error: nil, **properties, &block)
log(::Logger::INFO, template, error, properties, &block)
log(LogLevel::INFO, template, error, properties, &block)
end

def warn(template = nil, error: nil, **properties, &block)
log(::Logger::WARN, template, error, properties, &block)
log(LogLevel::WARN, template, error, properties, &block)
end

def error(template = nil, error: nil, **properties, &block)
log(::Logger::ERROR, template, error, properties, &block)
log(LogLevel::ERROR, template, error, properties, &block)
end

def fatal(template = nil, error: nil, **properties, &block)
log(::Logger::FATAL, template, error, properties, &block)
log(LogLevel::FATAL, template, error, properties, &block)
end

private

def log(level, template, error, properties, &block)
return true if @sinks.size == 0
return true if level < @min_level
return true if level < @level

if template.nil? && block_given?
template, properties = yield
Expand All @@ -49,20 +57,19 @@ def log(level, template, error, properties, &block)
error = properties[:error]
end

message = create_log_event(level, template, error, properties)
log_event = create_log_event(level, template, error, properties)

@sinks.each do |sink|
sink.log(message)
sink.log(log_event)
end

true
end

def create_log_event(level, template, error, properties)
template = Templates::Parser.parse(template)
message_properties = Properties::MessageProperties.new(properties)

Messages::LogEvent.new(level, template, error, message_properties)
Events::LogEvent.new(level, template, error, properties)
end
end
end
19 changes: 19 additions & 0 deletions lib/semlogr/logger_configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Semlogr
class LoggerConfiguration
attr_reader :level
attr_reader :sinks

def initialize
@level = ::Logger::DEBUG
@sinks = []
end

def min_level(level)
@level = level
end

def write_to(sink)
@sinks << sink
end
end
end
18 changes: 0 additions & 18 deletions lib/semlogr/properties/error_value.rb

This file was deleted.

15 changes: 0 additions & 15 deletions lib/semlogr/properties/log_event_value.rb

This file was deleted.

15 changes: 0 additions & 15 deletions lib/semlogr/properties/log_level_value.rb

This file was deleted.

19 changes: 0 additions & 19 deletions lib/semlogr/properties/message_properties.rb

This file was deleted.

Loading

0 comments on commit a9aa9ae

Please sign in to comment.