semlogr 0.3.0 → 0.3.1

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +7 -0
  4. data/Gemfile +2 -0
  5. data/README.md +1 -1
  6. data/Rakefile +2 -0
  7. data/bin/console +1 -0
  8. data/lib/semlogr/component_registry.rb +2 -0
  9. data/lib/semlogr/config/logger_config.rb +10 -1
  10. data/lib/semlogr/config/sink_config.rb +10 -1
  11. data/lib/semlogr/enrichers/event_type.rb +2 -0
  12. data/lib/semlogr/enrichers/host.rb +2 -0
  13. data/lib/semlogr/enrichers/log_context.rb +2 -0
  14. data/lib/semlogr/enrichers/property.rb +2 -0
  15. data/lib/semlogr/enrichers/thread.rb +2 -0
  16. data/lib/semlogr/error.rb +2 -0
  17. data/lib/semlogr/events/log_event.rb +3 -1
  18. data/lib/semlogr/formatters/json_formatter.rb +2 -0
  19. data/lib/semlogr/formatters/property_value_formatter.rb +13 -12
  20. data/lib/semlogr/formatters/text_formatter.rb +4 -2
  21. data/lib/semlogr/log_context.rb +2 -0
  22. data/lib/semlogr/log_severity.rb +2 -0
  23. data/lib/semlogr/logger.rb +2 -0
  24. data/lib/semlogr/null_logger.rb +2 -0
  25. data/lib/semlogr/properties/output_properties.rb +2 -0
  26. data/lib/semlogr/self_logger.rb +56 -0
  27. data/lib/semlogr/sinks/aggregate.rb +9 -1
  28. data/lib/semlogr/sinks/batching.rb +86 -0
  29. data/lib/semlogr/sinks/colored_console.rb +4 -2
  30. data/lib/semlogr/sinks/console.rb +2 -0
  31. data/lib/semlogr/sinks/enriching.rb +12 -1
  32. data/lib/semlogr/sinks/file.rb +2 -0
  33. data/lib/semlogr/sinks/filtering.rb +13 -1
  34. data/lib/semlogr/templates/parser.rb +19 -5
  35. data/lib/semlogr/templates/property_token.rb +32 -11
  36. data/lib/semlogr/templates/template.rb +2 -0
  37. data/lib/semlogr/templates/template_cache.rb +2 -0
  38. data/lib/semlogr/templates/text_token.rb +2 -0
  39. data/lib/semlogr/utils/bounded_queue.rb +41 -0
  40. data/lib/semlogr/version.rb +3 -1
  41. data/lib/semlogr.rb +6 -2
  42. data/samples/basic.rb +2 -0
  43. data/samples/context.rb +2 -0
  44. data/samples/enrichment.rb +2 -0
  45. data/samples/filtering.rb +2 -0
  46. data/samples/log_context.rb +2 -0
  47. data/samples/self_logger.rb +27 -0
  48. data/samples/sinks.rb +2 -0
  49. data/semlogr.gemspec +3 -0
  50. metadata +20 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1d29805d04a2f5a85ceb89d32355a7e14281fe0a91a29d51dea9598f2a62813
4
- data.tar.gz: af62ca05343ca10d137b0f9b5f3b0d634e9dd2f316857f8f0872732195b76543
3
+ metadata.gz: 72f3e3b75d0a87bbfaba4006891ae607b6ede75a90eb6abd1df4c63e61154197
4
+ data.tar.gz: c94f6f1201b911f7a4882d41b71b557ae5a9d3bafc6e37328b57bf35b6fd3181
5
5
  SHA512:
6
- metadata.gz: 4d2338b9270cd216909a23f16a8771e152230fd9b68fa492543de01ccc14a5871649bcba3abfca882deca43fb867e85d1f8ed6b7c34920539ce78fbbda969436
7
- data.tar.gz: ef241d71fa093dd5321be58abf8843e404e16409b506a9068ac9910bc27178a10c355e33a4c810f85176a365ddfdcb3a7e8971bd1ab8163f827a4c39fea0b8c5
6
+ metadata.gz: 37d8e017fb82402551aa2a43440b6eea26bc7127cf452a815762911d84def00640be109774d8032571e9f6d3dce433448235e7f884cc7cff823efbfe2ade9d41
7
+ data.tar.gz: f570b3e43ae0e442c3723ab73fbf36d6915509cb87e9478303502b04f3bc9b99840a98bc3df815c3db189bee9767a108af0cb16e5c9bf6fd87e76e72f369f48d
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.2
2
+ TargetRubyVersion: 2.3
3
3
 
4
4
  Documentation:
5
5
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ### 0.3.1
4
+
5
+ * Added batching sink providing ability to create sinks that reliably emit batches of events.
6
+ * Added initial version of property formatting, allowing standard Ruby format strings to be used to format property values.
7
+ * Added self logger to provide internal diagnostic information.
8
+ * Made it so that errors raised by sinks/enrichers/filters will not to crash the entire application. Instead they are swallowed and the error is written to the self log.
9
+
3
10
  ### 0.3.0
4
11
 
5
12
  * Moved LogContext
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
data/README.md CHANGED
@@ -23,7 +23,7 @@ then:
23
23
  Create an instance of the logger configuring one or more sinks.
24
24
 
25
25
  ```ruby
26
- require "semlogr"
26
+ require 'semlogr'
27
27
 
28
28
  Semlogr.logger = Semlogr.create_logger do |c|
29
29
  c.log_at :info
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
  require 'rubocop/rake_task'
data/bin/console CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'bundler/setup'
4
5
  require 'semlogr'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/error'
2
4
 
3
5
  module Semlogr
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/component_registry'
2
4
  require 'semlogr/sinks/aggregate'
3
5
  require 'semlogr/sinks/enriching'
@@ -25,7 +27,7 @@ module Semlogr
25
27
  end
26
28
 
27
29
  def enrich_with(enricher, *params)
28
- enricher = ComponentRegistry.resolve(:enricher, enricher, *params) if enricher.is_a?(Symbol)
30
+ enricher = resolve_enricher(enricher, params)
29
31
  @enrichers << enricher
30
32
  end
31
33
 
@@ -43,6 +45,13 @@ module Semlogr
43
45
 
44
46
  Logger.new(@min_severity, sink)
45
47
  end
48
+
49
+ private
50
+
51
+ def resolve_enricher(enricher, params)
52
+ return enricher unless enricher.is_a?(Symbol)
53
+ ComponentRegistry.resolve(:enricher, enricher, *params)
54
+ end
46
55
  end
47
56
  end
48
57
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/component_registry'
2
4
  require 'semlogr/sinks/enriching'
3
5
  require 'semlogr/sinks/filtering'
@@ -21,7 +23,7 @@ module Semlogr
21
23
  end
22
24
 
23
25
  def enrich_with(enricher, *params)
24
- enricher = ComponentRegistry.resolve(:enricher, enricher, *params) if enricher.is_a?(Symbol)
26
+ enricher = resolve_enricher(enricher, params)
25
27
  @enrichers << enricher
26
28
  end
27
29
 
@@ -39,6 +41,13 @@ module Semlogr
39
41
  sink = Sinks::Enriching.new(@enrichers, sink) if @enrichers.any?
40
42
  sink
41
43
  end
44
+
45
+ private
46
+
47
+ def resolve_enricher(enricher, params)
48
+ return enricher unless enricher.is_a?(Symbol)
49
+ ComponentRegistry.resolve(:enricher, enricher, *params)
50
+ end
42
51
  end
43
52
  end
44
53
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/component_registry'
2
4
 
3
5
  module Semlogr
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'socket'
2
4
  require 'semlogr/component_registry'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/log_context'
2
4
 
3
5
  module Semlogr
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/component_registry'
2
4
 
3
5
  module Semlogr
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/component_registry'
2
4
 
3
5
  module Semlogr
data/lib/semlogr/error.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semlogr
2
4
  class Error < StandardError
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'digest/xxhash'
2
4
  require 'semlogr/templates/parser'
3
5
 
@@ -45,7 +47,7 @@ module Semlogr
45
47
  end
46
48
 
47
49
  def to_s
48
- output = ''
50
+ output = +''
49
51
 
50
52
  render(output)
51
53
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'oj'
2
4
 
3
5
  module Semlogr
@@ -1,26 +1,27 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semlogr
2
4
  module Formatters
3
5
  class PropertyValueFormatter
4
- QUOTE = '"'.freeze
6
+ NO_VALUE = '(nil)'
7
+ NEW_LINE = "\n"
5
8
 
6
- def self.format(output, property_value)
7
- case property_value
9
+ def self.format(value)
10
+ case value
8
11
  when nil
9
- output << '(nil)'.freeze
12
+ NO_VALUE
10
13
  when String
11
- output << QUOTE
12
- output << property_value
13
- output << QUOTE
14
+ "\"#{value}\""
14
15
  when StandardError
15
- output << "#{property_value.class}: #{property_value.message}"
16
+ formatted_error = +"#{value.class}: #{value.message}"
16
17
 
17
- if property_value.backtrace
18
- output << "\n\s\s#{property_value.backtrace.join("\n\s\s")}"
18
+ if value.backtrace&.any?
19
+ formatted_error << "\n\s\s#{value.backtrace.join("\n\s\s")}"
19
20
  end
20
21
 
21
- output << "\n"
22
+ formatted_error << NEW_LINE
22
23
  else
23
- output << property_value.to_s
24
+ value.to_s
24
25
  end
25
26
  end
26
27
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/templates/parser'
2
4
  require 'semlogr/properties/output_properties'
3
5
  require 'semlogr/templates/property_token'
@@ -5,14 +7,14 @@ require 'semlogr/templates/property_token'
5
7
  module Semlogr
6
8
  module Formatters
7
9
  class TextFormatter
8
- DEFAULT_TEMPLATE = "[{timestamp}] {severity}: {message}\n{error}".freeze
10
+ DEFAULT_TEMPLATE = "[{timestamp}] {severity}: {message}\n{error}"
9
11
 
10
12
  def initialize(template: DEFAULT_TEMPLATE)
11
13
  @template = Templates::Parser.parse(template)
12
14
  end
13
15
 
14
16
  def format(log_event)
15
- output = ''
17
+ output = +''
16
18
  output_properties = Properties::OutputProperties.create(log_event)
17
19
 
18
20
  @template.tokens.each do |token|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semlogr
2
4
  class LogContext
3
5
  def self.current
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semlogr
2
4
  class LogSeverity
3
5
  include Comparable
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/config/logger_config'
2
4
  require 'semlogr/log_severity'
3
5
  require 'semlogr/events/log_event'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semlogr
2
4
  class NullLogger
3
5
  def debug?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semlogr
2
4
  module Properties
3
5
  class OutputProperties
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Semlogr
4
+ class SelfLogger
5
+ def self.debug(message, error = nil)
6
+ log(:debug, message, error)
7
+ end
8
+
9
+ def self.info(message, error = nil)
10
+ log(:info, message, error)
11
+ end
12
+
13
+ def self.warn(message, error = nil)
14
+ log(:warn, message, error)
15
+ end
16
+
17
+ def self.error(message, error = nil)
18
+ log(:error, message, error)
19
+ end
20
+
21
+ def self.fatal(message, error = nil)
22
+ log(:fatal, message, error)
23
+ end
24
+
25
+ class << self
26
+ attr_accessor :logger
27
+
28
+ private
29
+
30
+ def log(severity, message, error)
31
+ return unless logger
32
+
33
+ logger << format_message(severity, message, error)
34
+ end
35
+
36
+ def format_message(severity, message, error)
37
+ formatted = +"[#{Time.now.iso8601(3)}] #{severity.upcase}: #{message}"
38
+
39
+ if error
40
+ case error
41
+ when StandardError
42
+ formatted << "\n#{error.class}: #{error.message}"
43
+
44
+ if error.backtrace&.any?
45
+ formatted << "\n\s\s#{error.backtrace.join("\n\s\s")}"
46
+ end
47
+ else
48
+ formatted << "\n#{error}"
49
+ end
50
+ end
51
+
52
+ formatted << "\n"
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'semlogr/self_logger'
4
+
1
5
  module Semlogr
2
6
  module Sinks
3
7
  class Aggregate
@@ -7,7 +11,11 @@ module Semlogr
7
11
 
8
12
  def emit(log_event)
9
13
  @sinks.each do |sink|
10
- sink.emit(log_event)
14
+ begin
15
+ sink.emit(log_event)
16
+ rescue StandardError => e
17
+ SelfLogger.error("Failed to emit log event to sink #{sink.class}", e)
18
+ end
11
19
  end
12
20
  end
13
21
  end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'semlogr/utils/bounded_queue'
4
+ require 'timeout'
5
+
6
+ module Semlogr
7
+ module Sinks
8
+ class Batching
9
+ MAX_FLUSH_ATTEMPTS = 6
10
+
11
+ def initialize(opts = {})
12
+ @flush_interval = opts[:flush_interval] || 3
13
+ @final_flush_timeout = opts[:final_flush_timeout] || 60
14
+ @batch_size = opts[:batch_size] || 1_000
15
+ @queue_max_size = opts[:queue_max_size] || 100_000
16
+ @queue = Utils::BoundedQueue.new(@queue_max_size)
17
+ @flush_mutex = Mutex.new
18
+ @running = false
19
+
20
+ start_flush_thread
21
+
22
+ at_exit { stop_flush_thread }
23
+ end
24
+
25
+ def emit(log_event)
26
+ return unless @running
27
+
28
+ @queue.push(log_event)
29
+ end
30
+
31
+ private
32
+
33
+ def flush
34
+ @flush_mutex.synchronize do
35
+ loop do
36
+ log_events = @queue.pop_count(@batch_size)
37
+ success = emit_batch_with_retries(log_events)
38
+
39
+ break unless success
40
+ break if log_events.empty? || log_events.size < @batch_size
41
+ end
42
+ end
43
+ end
44
+
45
+ def emit_batch_with_retries(log_events)
46
+ return true if log_events.empty?
47
+
48
+ flush_attempts = 0
49
+
50
+ begin
51
+ emit_batch(log_events)
52
+ rescue StandardError
53
+ flush_attempts += 1
54
+
55
+ if flush_attempts <= MAX_FLUSH_ATTEMPTS
56
+ sleep 2**flush_attempts
57
+ retry
58
+ end
59
+
60
+ return false
61
+ end
62
+
63
+ true
64
+ end
65
+
66
+ def start_flush_thread
67
+ @running = true
68
+
69
+ Thread.new do
70
+ loop do
71
+ break unless @running
72
+
73
+ sleep @flush_interval
74
+ flush
75
+ end
76
+ end
77
+ end
78
+
79
+ def stop_flush_thread
80
+ @running = false
81
+
82
+ Timeout.timeout(@final_flush_timeout) { flush }
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/sinks/console'
2
4
  require 'semlogr/properties/output_properties'
3
5
 
4
6
  module Semlogr
5
7
  module Sinks
6
8
  class ColoredConsole
7
- DEFAULT_TEMPLATE = "[{timestamp}] {severity}: {message}\n{error}".freeze
9
+ DEFAULT_TEMPLATE = "[{timestamp}] {severity}: {message}\n{error}"
8
10
 
9
11
  LOG_SEVERITY_COLORS = {
10
12
  LogSeverity::DEBUG => :white,
@@ -26,7 +28,7 @@ module Semlogr
26
28
  end
27
29
 
28
30
  def emit(log_event)
29
- output = ''
31
+ output = +''
30
32
  output_properties = Properties::OutputProperties.create(log_event)
31
33
 
32
34
  @template.tokens.each do |token|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/formatters/text_formatter'
2
4
 
3
5
  module Semlogr
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'semlogr/self_logger'
4
+
1
5
  module Semlogr
2
6
  module Sinks
3
7
  class Enriching
@@ -7,7 +11,14 @@ module Semlogr
7
11
  end
8
12
 
9
13
  def emit(log_event)
10
- @enrichers.each { |enricher| enricher.enrich(log_event) }
14
+ @enrichers.each do |enricher|
15
+ begin
16
+ enricher.enrich(log_event)
17
+ rescue StandardError => e
18
+ SelfLogger.error("Failed to enrich log event using enricher #{enricher.class}", e)
19
+ end
20
+ end
21
+
11
22
  @sink.emit(log_event)
12
23
  end
13
24
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
  require 'semlogr/formatters/text_formatter'
3
5
 
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'semlogr/self_logger'
4
+
1
5
  module Semlogr
2
6
  module Sinks
3
7
  class Filtering
@@ -7,7 +11,15 @@ module Semlogr
7
11
  end
8
12
 
9
13
  def emit(log_event)
10
- filtered = @filters.any? { |filter| filter.call(log_event) }
14
+ filtered = @filters.any? do |filter|
15
+ begin
16
+ filter.call(log_event)
17
+ rescue StandardError => e
18
+ SelfLogger.error("Failed to filter log event using filter #{filter.class}", e)
19
+
20
+ false
21
+ end
22
+ end
11
23
 
12
24
  @sink.emit(log_event) unless filtered
13
25
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/templates/template'
2
4
  require 'semlogr/templates/text_token'
3
5
  require 'semlogr/templates/property_token'
@@ -8,8 +10,9 @@ module Semlogr
8
10
  class Parser
9
11
  @template_cache = TemplateCache.new(1000)
10
12
 
11
- PROPERTY_TOKEN_START = '{'.freeze
12
- PROPERTY_TOKEN_END = '}'.freeze
13
+ PROPERTY_TOKEN_START = '{'
14
+ PROPERTY_TOKEN_END = '}'
15
+ FILTER_TOKEN_START = ':'
13
16
 
14
17
  def self.parse(template)
15
18
  return Template::EMPTY unless template && !template.empty?
@@ -54,14 +57,25 @@ module Semlogr
54
57
 
55
58
  token = nil
56
59
  pos = start
60
+ filter_start = nil
57
61
 
58
62
  while pos < template.size
59
- if template[pos] == PROPERTY_TOKEN_END
63
+ case template[pos]
64
+ when PROPERTY_TOKEN_END
60
65
  raw_text = template[start..pos]
61
- property_name = raw_text[1..-2]
62
- token = PropertyToken.new(raw_text, property_name.to_sym)
66
+ filter = nil
67
+
68
+ if filter_start.nil?
69
+ property_name = template[start + 1..pos - 1]
70
+ else
71
+ property_name = template[start + 1..filter_start - 1]
72
+ filter = template[filter_start + 1..pos - 1]
73
+ end
63
74
 
75
+ token = PropertyToken.new(raw_text, property_name.to_sym, filter)
64
76
  return [token, pos + 1]
77
+ when FILTER_TOKEN_START
78
+ filter_start ||= pos
65
79
  end
66
80
 
67
81
  pos += 1
@@ -1,30 +1,41 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/formatters/property_value_formatter'
4
+ require 'semlogr/self_logger'
2
5
 
3
6
  module Semlogr
4
7
  module Templates
5
8
  class PropertyToken
6
- attr_accessor :property_name
9
+ attr_reader :raw_text, :property_name, :format_string
7
10
 
8
- def initialize(raw_text, property_name)
11
+ def initialize(raw_text, property_name, format = nil)
9
12
  @raw_text = raw_text
10
13
  @property_name = property_name
14
+ @format_string = format ? "%#{format}" : nil
11
15
  end
12
16
 
13
17
  def render(output, properties)
14
- if properties.key?(@property_name)
15
- property_value = properties[@property_name]
16
-
17
- Formatters::PropertyValueFormatter.format(output, property_value)
18
- else
19
- output << @raw_text
20
- end
18
+ output <<
19
+ if properties.key?(property_name)
20
+ format_property_value(properties[property_name])
21
+ else
22
+ raw_text
23
+ end
24
+ rescue StandardError => e
25
+ SelfLogger.error("Failed to render property token: #{property_name}", e)
26
+
27
+ output << raw_text
21
28
  end
22
29
 
23
30
  def ==(other)
24
31
  return false unless other
32
+ return false unless other.respond_to?(:raw_text)
25
33
  return false unless other.respond_to?(:property_name)
34
+ return false unless other.respond_to?(:format_string)
26
35
 
27
- @property_name == other.property_name
36
+ raw_text == other.raw_text && \
37
+ property_name == other.property_name && \
38
+ format_string == other.format_string
28
39
  end
29
40
 
30
41
  def eql?(other)
@@ -32,7 +43,17 @@ module Semlogr
32
43
  end
33
44
 
34
45
  def hash
35
- @property_name.hash
46
+ [raw_text, property_name, format_string].hash
47
+ end
48
+
49
+ private
50
+
51
+ def format_property_value(property_value)
52
+ if format_string
53
+ format(format_string, property_value)
54
+ else
55
+ Formatters::PropertyValueFormatter.format(property_value)
56
+ end
36
57
  end
37
58
  end
38
59
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'semlogr/templates/text_token'
2
4
 
3
5
  module Semlogr
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'lru_redux'
2
4
 
3
5
  module Semlogr
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semlogr
2
4
  module Templates
3
5
  class TextToken
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+
5
+ module Semlogr
6
+ module Utils
7
+ class BoundedQueue
8
+ def initialize(max_size)
9
+ @max_size = max_size
10
+ @queue = Queue.new
11
+ @queue_mutex = Mutex.new
12
+ end
13
+
14
+ def size
15
+ @queue.size
16
+ end
17
+
18
+ def push(item)
19
+ @queue_mutex.synchronize do
20
+ return if size >= @max_size
21
+
22
+ @queue << item
23
+ end
24
+ end
25
+
26
+ def pop
27
+ @queue.pop
28
+ end
29
+
30
+ def pop_count(count)
31
+ items = []
32
+
33
+ @queue_mutex.synchronize do
34
+ items << @queue.pop until @queue.empty? || items.size == count
35
+ end
36
+
37
+ items
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Semlogr
2
- VERSION = '0.3.0'.freeze
4
+ VERSION = '0.3.1'
3
5
  end
data/lib/semlogr.rb CHANGED
@@ -1,7 +1,10 @@
1
- require 'semlogr/version'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'semlogr/logger'
3
- require 'semlogr/null_logger'
4
4
  require 'semlogr/log_context'
5
+ require 'semlogr/null_logger'
6
+ require 'semlogr/self_logger'
7
+ require 'semlogr/version'
5
8
 
6
9
  # Built-in enrichers
7
10
  require 'semlogr/enrichers/event_type'
@@ -11,6 +14,7 @@ require 'semlogr/enrichers/property'
11
14
  require 'semlogr/enrichers/thread'
12
15
 
13
16
  # Built-in sinks
17
+ require 'semlogr/sinks/batching'
14
18
  require 'semlogr/sinks/console'
15
19
  require 'semlogr/sinks/colored_console'
16
20
  require 'semlogr/sinks/file'
data/samples/basic.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/setup'
2
4
  require 'semlogr'
3
5
 
data/samples/context.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/setup'
2
4
  require 'semlogr'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/setup'
2
4
  require 'semlogr'
3
5
 
data/samples/filtering.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/setup'
2
4
  require 'semlogr'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/setup'
2
4
  require 'semlogr'
3
5
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'semlogr'
5
+
6
+ class TestSink
7
+ def emit(_log_event)
8
+ raise StandardError, 'emit error'
9
+ end
10
+ end
11
+
12
+ class TestEnricher
13
+ def enrich(_log_event)
14
+ raise StandardError, 'enrich error'
15
+ end
16
+ end
17
+
18
+ Semlogr::SelfLogger.logger = STDERR
19
+ Semlogr.logger = Semlogr::Logger.create do |c|
20
+ c.write_to :console
21
+
22
+ c.write_to TestSink.new
23
+ c.enrich_with TestEnricher.new
24
+ c.filter ->(_log_event) { raise StandardError, 'filter error' }
25
+ end
26
+
27
+ Semlogr.info('Customer {id} checked out', id: 123)
data/samples/sinks.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/setup'
2
4
  require 'semlogr'
3
5
 
data/semlogr.gemspec CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path('lib', __dir__)
2
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
5
 
@@ -31,4 +33,5 @@ Gem::Specification.new do |spec|
31
33
  spec.add_development_dependency 'rspec', '~> 3.7'
32
34
  spec.add_development_dependency 'rubocop', '0.53'
33
35
  spec.add_development_dependency 'simplecov', '~>0.15'
36
+ spec.add_development_dependency 'timecop', '~>0.9'
34
37
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: semlogr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Sedich
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-17 00:00:00.000000000 Z
11
+ date: 2018-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: digest-xxhash
@@ -164,6 +164,20 @@ dependencies:
164
164
  - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0.15'
167
+ - !ruby/object:Gem::Dependency
168
+ name: timecop
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.9'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.9'
167
181
  description: A modern semantic logger for Ruby inspired by Serilog.
168
182
  email:
169
183
  - stefan.sedich@gmail.com
@@ -200,7 +214,9 @@ files:
200
214
  - lib/semlogr/logger.rb
201
215
  - lib/semlogr/null_logger.rb
202
216
  - lib/semlogr/properties/output_properties.rb
217
+ - lib/semlogr/self_logger.rb
203
218
  - lib/semlogr/sinks/aggregate.rb
219
+ - lib/semlogr/sinks/batching.rb
204
220
  - lib/semlogr/sinks/colored_console.rb
205
221
  - lib/semlogr/sinks/console.rb
206
222
  - lib/semlogr/sinks/enriching.rb
@@ -211,12 +227,14 @@ files:
211
227
  - lib/semlogr/templates/template.rb
212
228
  - lib/semlogr/templates/template_cache.rb
213
229
  - lib/semlogr/templates/text_token.rb
230
+ - lib/semlogr/utils/bounded_queue.rb
214
231
  - lib/semlogr/version.rb
215
232
  - samples/basic.rb
216
233
  - samples/context.rb
217
234
  - samples/enrichment.rb
218
235
  - samples/filtering.rb
219
236
  - samples/log_context.rb
237
+ - samples/self_logger.rb
220
238
  - samples/sinks.rb
221
239
  - semlogr.gemspec
222
240
  homepage: https://github.com/semlogr/semlogr