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 +21 -5
- data/lib/structured_event_logger.rb +17 -42
- data/lib/structured_event_logger/human_readable_logger.rb +40 -0
- data/lib/structured_event_logger/json_writer.rb +15 -0
- data/lib/structured_event_logger/version.rb +1 -1
- data/test/structured_event_logger_test.rb +20 -12
- data/test/test_helper.rb +1 -0
- metadata +4 -2
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# StructuredEventLogger
|
2
2
|
|
3
|
-
Structured event logger that
|
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
|
-
|
23
|
-
|
24
|
-
event_logger = StructuredEventLogger.new(
|
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
|
-
|
8
|
-
BOLD = "\e[1m"
|
4
|
+
attr_reader :endpoints, :default_context
|
9
5
|
|
10
|
-
|
11
|
-
|
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
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
@@ -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
|
-
|
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
|
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
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
|
+
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-
|
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
|