structured-event-logger 0.0.4 → 0.0.5

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.
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # StructuredEventLogger
2
2
 
3
- Structured event logger that writes events to both a human readable log and a JSON formatted log
3
+ Structured event logger that submits events to a list of listeners, including
4
+ human readable logs, json formatted event streams, and other endpoints.
4
5
 
5
6
  ## Installation
6
7
 
@@ -18,10 +19,13 @@ Or install it yourself as:
18
19
 
19
20
  ## Usage
20
21
 
21
- # Creating an instance
22
- json_logger = File.open(Rails.root.join("log", "event.log"), "a")
23
- human_readable_logger = Rails.logger
24
- event_logger = StructuredEventLogger.new(json_logger, human_readable_logger)
22
+ # Creating an instance of a StructuredEventLogger with several endpoints.
23
+ # The listeners provided to the constructors should respond to #log_event.
24
+ json_io = File.open(Rails.root.join("log", "event.log"), "a")
25
+ event_logger = StructuredEventLogger.new([
26
+ StructuredEventLogger::HumanReadableLogger.new(Rails.logger),
27
+ StructuredEventLogger::JsonWriter.new(json_io)
28
+ ])
25
29
 
26
30
  # Basic usage
27
31
  event_logger.event('scope', event, field: 'value', other_field: 'other value')
@@ -36,6 +40,18 @@ Or install it yourself as:
36
40
  # later, while processing a request inside that filter
37
41
  event_logger.event('scope', 'event', other_value: 'blah') # will also include { my_value: 'whatever' }
38
42
 
43
+ ## Fields
44
+
45
+ The default event fields that this library sets are prefixed with `event_`:
46
+
47
+ - `event_scope`: scope of the event, the first parameter to the `event` call.
48
+ - `event_name`: name of the event, the second parameter to the `event` call.
49
+ - `event_uuid`: A unique identifier for the event generated using `SecureRandom.uuid`.
50
+ - `event_timestamp`: The timestamp of the event, set to `Time.now.utc`.
51
+
52
+ All these fields can be overriden by passing new values to the context hash, i.e. the
53
+ third parameter to the `event` call.
54
+
39
55
  ## Contributing
40
56
 
41
57
  1. Fork it
@@ -1,28 +1,13 @@
1
- require 'logger'
2
1
  require 'securerandom'
3
- require 'active_support/json'
4
- require 'active_support/log_subscriber'
5
2
 
6
3
  class StructuredEventLogger
7
- CLEAR = "\e[0m"
8
- BOLD = "\e[1m"
4
+ attr_reader :endpoints, :default_context
9
5
 
10
- # Colors
11
- MAGENTA = "\e[35m"
12
- CYAN = "\e[36m"
13
- WHITE = "\e[37m"
6
+ def initialize(endpoints = [])
7
+ @endpoints = endpoints
14
8
 
15
- attr_reader :json_io, :unstructured_logger, :colorize_logging, :default_context
16
-
17
- def initialize(json_io, unstructured_logger = nil)
18
- @json_io, @unstructured_logger = json_io, unstructured_logger
19
9
  @thread_contexts = {}
20
10
  @default_context = {}
21
- @colorize_logging = ActiveSupport::LogSubscriber.colorize_logging
22
- end
23
-
24
- def log(msg = nil)
25
- unstructured_logger.add(nil, msg)
26
11
  end
27
12
 
28
13
  def event(scope, event, content = {})
@@ -35,25 +20,6 @@ class StructuredEventLogger
35
20
 
36
21
  private
37
22
 
38
- def format_hash(scope, event, hash, separator = ', ')
39
- @odd = !@odd
40
- message = hash.map {|k, v| "#{k}=#{escape(v)}"}.join(separator)
41
- if @colorize_logging
42
- " #{@odd ? CYAN : MAGENTA}#{BOLD}[#{scope}] #{event}: #{WHITE}#{message}#{CLEAR}"
43
- else
44
- " [#{scope}] #{event}: #{message}"
45
- end
46
- end
47
-
48
- def escape(value)
49
- output = value.to_s
50
- if output =~ /[\s"\\]/
51
- '"' + output.gsub('\\', '\\\\\\').gsub('"', '\\"') + '"'
52
- else
53
- output
54
- end
55
- end
56
-
57
23
  def flatten_hash(hash, keys = nil, separator = "_")
58
24
  flat_hash = {}
59
25
  hash.each_pair do |key, val|
@@ -68,14 +34,23 @@ class StructuredEventLogger
68
34
  end
69
35
 
70
36
  def log_event(scope, event, hash)
71
- unstructured_logger.add(nil, format_hash(scope, event, hash)) if unstructured_logger
72
-
73
- hash = hash.merge(@default_context.merge(context)).merge(event_name: event, event_scope: scope, event_uuid: SecureRandom.uuid)
74
- hash = { event_timestamp: Time.now.utc }.merge(hash)
75
- json_io.write("#{MultiJson.encode(hash)}\n")
37
+ record = @default_context.merge(context)
38
+ record.update(event_name: event, event_scope: scope, event_uuid: SecureRandom.uuid, event_timestamp: Time.now.utc)
39
+ record.update(hash)
40
+
41
+ endpoints.each do |endpoint|
42
+ begin
43
+ endpoint.call(scope, event, hash, record)
44
+ rescue => e
45
+ $stderr.write("Failed to submit event #{scope}/#{event} to #{endpoint.inspect}: #{e.message}.\n")
46
+ end
47
+ end
76
48
  end
77
49
 
78
50
  def thread_key
79
51
  Thread.current
80
52
  end
81
53
  end
54
+
55
+ require 'structured_event_logger/json_writer'
56
+ require 'structured_event_logger/human_readable_logger'
@@ -0,0 +1,40 @@
1
+ require 'active_support/log_subscriber'
2
+
3
+ class StructuredEventLogger::HumanReadableLogger
4
+
5
+ CLEAR = "\e[0m"
6
+ BOLD = "\e[1m"
7
+
8
+ # Colors
9
+ MAGENTA = "\e[35m"
10
+ CYAN = "\e[36m"
11
+ WHITE = "\e[37m"
12
+
13
+ attr_accessor :logger, :colorize, :log_level
14
+
15
+ def initialize(logger, colorize = ActiveSupport::LogSubscriber.colorize_logging, log_level = nil)
16
+ @logger, @colorize, @log_level = logger, colorize, log_level
17
+ end
18
+
19
+
20
+ def call(scope, event, hash, decorated_hash)
21
+ logger.add(log_level, format_hash(scope, event, hash))
22
+ end
23
+
24
+ private
25
+
26
+ def format_hash(scope, event, hash, separator = ', ')
27
+ @odd = !@odd
28
+ message = hash.map {|k, v| "#{k}=#{escape(v)}"}.join(separator)
29
+ if @colorize
30
+ " #{@odd ? CYAN : MAGENTA}#{BOLD}[#{scope}] #{event}: #{WHITE}#{message}#{CLEAR}"
31
+ else
32
+ " [#{scope}] #{event}: #{message}"
33
+ end
34
+ end
35
+
36
+ def escape(value)
37
+ output = value.to_s
38
+ output =~ /[\s"\\]/ ? output.inspect : output
39
+ end
40
+ end
@@ -0,0 +1,15 @@
1
+ require 'multi_json'
2
+ require 'active_support/json'
3
+
4
+ class StructuredEventLogger::JsonWriter
5
+
6
+ attr_reader :io
7
+
8
+ def initialize(io)
9
+ @io = io
10
+ end
11
+
12
+ def call(scope, event, hash, record)
13
+ io.write(MultiJson.encode(record) + "\n")
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  class StructuredEventLogger
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -4,22 +4,19 @@ require 'stringio'
4
4
  class StructuredEventLoggerTest < Minitest::Test
5
5
  def setup
6
6
  ActiveSupport::LogSubscriber.colorize_logging = false
7
-
8
- @json_io = StringIO.new
7
+
9
8
  @unstructured_logger = Logger.new(@nonstructured_io = StringIO.new)
10
9
  @unstructured_logger.formatter = proc { |_, _, _, msg| "#{msg}\n" }
11
- @event_logger = StructuredEventLogger.new(@json_io, @unstructured_logger)
10
+
11
+ @event_logger = StructuredEventLogger.new([
12
+ StructuredEventLogger::HumanReadableLogger.new(@unstructured_logger),
13
+ StructuredEventLogger::JsonWriter.new(@json_io = StringIO.new)
14
+ ])
12
15
 
13
16
  Time.stubs(:now).returns(Time.parse('2012-01-01T05:00:00Z'))
14
17
  SecureRandom.stubs(:uuid).returns('aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee')
15
18
  end
16
19
 
17
- def test_should_log_msg_to_buffered_logger
18
- @event_logger.log "a message"
19
- assert_equal "a message\n", @nonstructured_io.string
20
- assert @json_io.string.empty?
21
- end
22
-
23
20
  def test_should_log_event_to_both_loggers
24
21
  @event_logger.event "render", "error", {:status => "status", :message => "message"}
25
22
 
@@ -37,14 +34,25 @@ class StructuredEventLoggerTest < Minitest::Test
37
34
  assert_last_event_contains_value '2012-01-01T05:00:00Z', :event_timestamp
38
35
  end
39
36
 
40
- def test_overwriting_default_properties
37
+ def test_overwriting_default_properties_using_hash
41
38
  @event_logger.event :original, :original, :event_scope => 'overwritten', :event_name => 'overwritten',
42
39
  :event_timestamp => Time.parse('1912-01-01T04:00:00Z'), :event_uuid => 'overwritten'
43
40
 
41
+ assert_last_event_contains_value 'overwritten', :event_scope
42
+ assert_last_event_contains_value 'overwritten', :event_name
43
+ assert_last_event_contains_value 'overwritten', :event_uuid
44
+ assert_last_event_contains_value '1912-01-01T04:00:00Z', :event_timestamp
45
+ end
46
+
47
+ def test_overwriting_default_properties_using_context
48
+ @event_logger.default_context[:event_name] = 'overwritten'
49
+ Thread.new do
50
+ @event_logger.context[:event_scope] = 'overwritten'
51
+ @event_logger.event :original, :original
52
+ end.join
53
+
44
54
  assert_last_event_contains_value 'original', :event_scope
45
55
  assert_last_event_contains_value 'original', :event_name
46
- assert_last_event_contains_value 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', :event_uuid
47
- assert_last_event_contains_value '1912-01-01T04:00:00Z', :event_timestamp
48
56
  end
49
57
 
50
58
  def test_should_log_flatten_hash
data/test/test_helper.rb CHANGED
@@ -2,6 +2,7 @@ require 'bundler/setup'
2
2
  require 'minitest/autorun'
3
3
  require 'minitest/pride'
4
4
  require 'mocha/setup'
5
+ require 'logger'
5
6
 
6
7
  $LOAD_PATH.unshift File.expand_path('../lib', File.dirname(__FILE__))
7
8
  require 'structured_event_logger'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: structured-event-logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2013-08-09 00:00:00.000000000 Z
15
+ date: 2013-08-13 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: activesupport
@@ -125,6 +125,8 @@ files:
125
125
  - Rakefile
126
126
  - lib/structured-event-logger.rb
127
127
  - lib/structured_event_logger.rb
128
+ - lib/structured_event_logger/human_readable_logger.rb
129
+ - lib/structured_event_logger/json_writer.rb
128
130
  - lib/structured_event_logger/version.rb
129
131
  - structured-event-logger.gemspec
130
132
  - test/structured_event_logger_test.rb