lorekeeper 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +104 -0
- data/Rakefile +63 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/lorekeeper.rb +4 -0
- data/lib/lorekeeper/fast_logger.rb +85 -0
- data/lib/lorekeeper/json_logger.rb +128 -0
- data/lib/lorekeeper/multi_logger.rb +22 -0
- data/lib/lorekeeper/version.rb +5 -0
- data/lorekeeper.gemspec +33 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 71ffd469643f224ae00f00a43a2d1b3722c1bf6b
|
4
|
+
data.tar.gz: 77ed9aee28a33c8066fb3a2a9c73f07ad71ecbf3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 84a7111da82f6cb7d23ae21c27bdf72c6af712a270f98dda7f771d3ba3934c15d9df47f1cbdbfe40655ec48c149c52f4a10c76e8ade212a8eaf21ee8fd40b323
|
7
|
+
data.tar.gz: 7de9032c4d6aba109fa72dc9f50b73e40256ff668cc6cd79b5a1120c4826bd1abffd2f155060361cdeabbb43ab09aace4b39a123d1a74fa01c7a36f98ed6fbd3
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Jordi Polo
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# Lorekeeper
|
2
|
+
|
3
|
+
LoreKeeper contains a highly optimized JSON logger. It outputs messages as JSON and let the users to add their own customized fields.
|
4
|
+
When used without extra fields it outputs 20% faster than the standard Logger for messages not longer than one line of text.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'lorekeeper'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### Normal logging methods
|
22
|
+
|
23
|
+
LoreKeeper::JSONLogger API is compatible with standard lib's Logger's. Level is not showed in the output.
|
24
|
+
|
25
|
+
```Ruby
|
26
|
+
logger.error("This is a message")
|
27
|
+
```
|
28
|
+
|
29
|
+
Will output:
|
30
|
+
```
|
31
|
+
{ "message": "This is a message", "timestamp": "1970-01-01T00:00:00.000+0100" }
|
32
|
+
```
|
33
|
+
|
34
|
+
Timestamps use ISO8601
|
35
|
+
Messages are json escaped so the total result is JSON parseable.
|
36
|
+
|
37
|
+
|
38
|
+
### Adding keys to the output
|
39
|
+
|
40
|
+
Keys can be added to the output at any moment. These keys will be output in each message till they are removed again. If you want to output keys in only one message use the _with_data method instead.
|
41
|
+
|
42
|
+
Keys can be added using the `add_fields` method which accepts a hash:
|
43
|
+
|
44
|
+
```Ruby
|
45
|
+
logger.add_fields( 'role' => 'backend' )
|
46
|
+
logger.error("This is a message")
|
47
|
+
logger.warning("This is another message")
|
48
|
+
```
|
49
|
+
|
50
|
+
Will output:
|
51
|
+
```json
|
52
|
+
{ "message": "This is a message", "timestamp": "1970-01-01T00:00:00.000+0100", "role": "backend" }
|
53
|
+
{ "message": "This is another message", "timestamp": "1970-01-01T00:00:00.000+0100", "role": "backend" }
|
54
|
+
```
|
55
|
+
|
56
|
+
Because of speed purposes the JSON dumping is done as simply as possible. If you provide a hash of keys like:
|
57
|
+
```ruby
|
58
|
+
{ key: 'value' }
|
59
|
+
```
|
60
|
+
The output will include:
|
61
|
+
```json
|
62
|
+
{ ":key": "value" }
|
63
|
+
```
|
64
|
+
|
65
|
+
|
66
|
+
### Logging methods with data
|
67
|
+
|
68
|
+
All methods (info, debug, etc.) has a _with_data equivalent: "info_with_data", "debug_with_data".
|
69
|
+
These methods accept and extra hash to add it to the JSON.
|
70
|
+
|
71
|
+
```Ruby
|
72
|
+
logger.error_with_data('message', {data1: 'Extra data', data2: 'Extra data2'})
|
73
|
+
```
|
74
|
+
|
75
|
+
Will output:
|
76
|
+
```json
|
77
|
+
{ "message": "This is a message", "timestamp": "1970-01-01T00:00:00.000+0100", "data": {"data1": "Extra data", "data2": "Extra data2"} }
|
78
|
+
```
|
79
|
+
|
80
|
+
|
81
|
+
### Logging exceptions
|
82
|
+
|
83
|
+
There is a method to help you log exceptions in an standard way.
|
84
|
+
|
85
|
+
```Ruby
|
86
|
+
rescue StandardError => e
|
87
|
+
logger.exception(e)
|
88
|
+
```
|
89
|
+
|
90
|
+
Will output:
|
91
|
+
```json
|
92
|
+
{ "message": "#{e.message}", "timestamp": "1970-01-01T00:00:00.000+0100", "exception": "<exception name>", "stack": ["<stacktraceline1>", "<stacktraceline2>"] }
|
93
|
+
```
|
94
|
+
|
95
|
+
|
96
|
+
## Contributing
|
97
|
+
|
98
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/lorekeeper.
|
99
|
+
|
100
|
+
|
101
|
+
## License
|
102
|
+
|
103
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
104
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'securerandom'
|
4
|
+
require 'benchmark/ips'
|
5
|
+
require 'byebug'
|
6
|
+
require 'rbtrace'
|
7
|
+
|
8
|
+
$LOAD_PATH.unshift(File.expand_path("../lib", __FILE__))
|
9
|
+
$LOAD_PATH.uniq!
|
10
|
+
|
11
|
+
require 'lorekeeper'
|
12
|
+
require 'logger'
|
13
|
+
|
14
|
+
def create_logger
|
15
|
+
logfile = Tempfile.new('my_test_log.log')
|
16
|
+
extra_fields = {
|
17
|
+
machine:"Verylongmachinenametobe-Pro.local",
|
18
|
+
component: 'Gilean', version: '0.1.1', trace_id: SecureRandom.hex(16), span_id: SecureRandom.hex(16), parent_span_id: SecureRandom.hex(16)
|
19
|
+
}
|
20
|
+
log = Lorekeeper::JSONLogger.new(logfile)
|
21
|
+
log.add_fields(extra_fields)
|
22
|
+
log
|
23
|
+
end
|
24
|
+
|
25
|
+
def create_simple_logger
|
26
|
+
logfile = Tempfile.new('my_test_log.log')
|
27
|
+
::Logger.new(logfile.path)
|
28
|
+
end
|
29
|
+
|
30
|
+
# This task is used to help development of Lorekeeper. Use together with rbtrace
|
31
|
+
desc "Runs the code once, sleeping to allow you to attach to it with rbtrace"
|
32
|
+
task :run_once do
|
33
|
+
contents = 'This is a test, this is only a test. Do not worry about these contents.'
|
34
|
+
long_contents = contents * 100
|
35
|
+
|
36
|
+
log = create_logger
|
37
|
+
sleep(10)
|
38
|
+
log.error(long_contents)
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# This task is used to help development of Lorekeeer. Make sure it is fast enough for your app.
|
43
|
+
desc "Runs benchmarks for the library."
|
44
|
+
task :benchmark do
|
45
|
+
|
46
|
+
contents = 'This is a test, this is only a test. Do not worry about these contents.'
|
47
|
+
long_contents = contents * 100
|
48
|
+
|
49
|
+
log = create_logger
|
50
|
+
simple_log = create_simple_logger
|
51
|
+
|
52
|
+
Benchmark.ips do |bm|
|
53
|
+
bm.report("short content") { log.error(contents) }
|
54
|
+
bm.report("Logger short content") { simple_log.info(contents) }
|
55
|
+
bm.report("long content") { log.info(long_contents) }
|
56
|
+
bm.report("Logger long content") { simple_log.info(long_contents) }
|
57
|
+
bm.compare!
|
58
|
+
end
|
59
|
+
|
60
|
+
puts "i/s means the number of log messages written into a file per second"
|
61
|
+
|
62
|
+
end
|
63
|
+
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "lorekeeper"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/lib/lorekeeper.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# The comment above will make all strings in a current file frozen
|
3
|
+
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
module Lorekeeper
|
7
|
+
|
8
|
+
# Very simple, very fast logger
|
9
|
+
class FastLogger
|
10
|
+
include ::Logger::Severity # contains the levels constants: DEBUG, ERROR, etc.
|
11
|
+
attr_accessor :level # Current level, default: DEBUG
|
12
|
+
attr_accessor :formatter # Just for compatibility with Logger, not used
|
13
|
+
|
14
|
+
def debug?; level <= DEBUG; end
|
15
|
+
def info?; level <= INFO; end
|
16
|
+
def warn?; level <= WARN; end
|
17
|
+
def error?; level <= ERROR; end
|
18
|
+
def fatal?; level <= FATAL; end
|
19
|
+
|
20
|
+
def initialize(file)
|
21
|
+
@level = DEBUG
|
22
|
+
@iodevice = LogDevice.new(file)
|
23
|
+
end
|
24
|
+
|
25
|
+
LOGGING_METHODS = %i(debug info warn error fatal)
|
26
|
+
METHOD_SEVERITY_MAP = {debug: DEBUG, info: INFO, warn: WARN, error: ERROR, fatal: FATAL}
|
27
|
+
|
28
|
+
# We define the behaviour of all the usual logging methods
|
29
|
+
# We support a string as a parameter and also a block
|
30
|
+
LOGGING_METHODS.each do |method_name|
|
31
|
+
define_method method_name.to_s, ->(message_param = nil, &block) do
|
32
|
+
return true if METHOD_SEVERITY_MAP[method_name] < @level
|
33
|
+
message = message_param || (block && block.call)
|
34
|
+
log_data(method_name, message.freeze)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# inherited classes probably want to reimplement this
|
39
|
+
def log_data(_method_sym, message)
|
40
|
+
@iodevice.write(message)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
require 'monitor'
|
46
|
+
class LogDeviceMutex
|
47
|
+
include MonitorMixin
|
48
|
+
end
|
49
|
+
|
50
|
+
class LogDevice
|
51
|
+
|
52
|
+
def initialize(file)
|
53
|
+
@iodevice = to_iodevice(file)
|
54
|
+
@iomutex = LogDeviceMutex.new
|
55
|
+
end
|
56
|
+
|
57
|
+
def write(message)
|
58
|
+
return unless @iodevice
|
59
|
+
@iomutex.synchronize do
|
60
|
+
@iodevice.write(message)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def to_iodevice(file)
|
67
|
+
return nil unless file
|
68
|
+
iodevice = if file.respond_to?(:write) and file.respond_to?(:close)
|
69
|
+
file
|
70
|
+
else
|
71
|
+
open_logfile(file)
|
72
|
+
end
|
73
|
+
iodevice.sync = true if iodevice.respond_to?(:sync=)
|
74
|
+
iodevice
|
75
|
+
end
|
76
|
+
|
77
|
+
def open_logfile(filename)
|
78
|
+
File.open(filename, (File::WRONLY | File::APPEND))
|
79
|
+
rescue Errno::ENOENT => e
|
80
|
+
puts "File #{filename} can't be open for logging. #{e.message}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# The comment above will make all strings in a current file frozen
|
3
|
+
require 'oj'
|
4
|
+
require 'lorekeeper/fast_logger'
|
5
|
+
|
6
|
+
module Lorekeeper
|
7
|
+
# The JSONLogger provides a logger which will output messages in JSON format
|
8
|
+
class JSONLogger < FastLogger
|
9
|
+
|
10
|
+
def initialize(file)
|
11
|
+
reset_state
|
12
|
+
@base_fields = { MESSAGE => '', TIMESTAMP => '' }
|
13
|
+
super(file)
|
14
|
+
end
|
15
|
+
|
16
|
+
def current_fields
|
17
|
+
state[:base_fields]
|
18
|
+
end
|
19
|
+
|
20
|
+
def state
|
21
|
+
Thread.current[THREAD_KEY] ||= { base_fields: @base_fields.dup, extra_fields: {} }
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset_state
|
25
|
+
Thread.current[THREAD_KEY] = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# Delegates methods to the existing Logger instance
|
29
|
+
# We are extending the logger API with methods error_with_data, etc
|
30
|
+
LOGGING_METHODS.each do |method_name|
|
31
|
+
define_method "#{method_name}_with_data", ->(message_param = nil, data = {}, &block) do
|
32
|
+
return true if METHOD_SEVERITY_MAP[method_name] < @level
|
33
|
+
extra_fields = {'data' => (data || {}) }
|
34
|
+
message = message_param || (block && block.call)
|
35
|
+
with_extra_fields(extra_fields) { log_data(method_name, message.freeze) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_thread_unsafe_fields(fields)
|
40
|
+
remove_invalid_fields(fields)
|
41
|
+
@base_fields.merge!(fields)
|
42
|
+
reset_state # Forcing to recreate the thread safe information
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove_thread_unsafe_fields(fields)
|
46
|
+
[*fields].each do |field|
|
47
|
+
@base_fields.delete(field)
|
48
|
+
end
|
49
|
+
reset_state
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_fields(fields)
|
53
|
+
remove_invalid_fields(fields)
|
54
|
+
state.fetch(:base_fields).merge!(fields)
|
55
|
+
end
|
56
|
+
|
57
|
+
def remove_fields(fields)
|
58
|
+
[*fields].each do |field|
|
59
|
+
state.fetch(:base_fields).delete(field)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param exception: instance of a class inheriting from Exception
|
64
|
+
# We will output backtrace twice. Once inside the stack so it can be parsed by software
|
65
|
+
# And the other inside the message so it is readable to humans
|
66
|
+
def exception(exception, custom_message = nil, custom_data = nil)
|
67
|
+
if exception.is_a?(Exception)
|
68
|
+
backtrace = exception.backtrace || []
|
69
|
+
exception_fields = {
|
70
|
+
'exception' => "#{exception.class}: #{exception.message}",
|
71
|
+
'stack' => backtrace
|
72
|
+
}
|
73
|
+
exception_fields['data'] = custom_data if custom_data
|
74
|
+
|
75
|
+
message = custom_message || exception.message
|
76
|
+
with_extra_fields(exception_fields) { log_data(:error, message) }
|
77
|
+
else
|
78
|
+
log_data(:warning, 'Logger exception called without exception class.')
|
79
|
+
error_with_data("#{exception.class}: #{exception.inspect} #{custom_message}", custom_data)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
THREAD_KEY = 'lorekeeper_jsonlogger_key'.freeze #Shared by all threads but unique by thread
|
86
|
+
MESSAGE = 'message'.freeze
|
87
|
+
TIMESTAMP = 'timestamp'.freeze
|
88
|
+
DATE_FORMAT = '%FT%T.%L%z'.freeze
|
89
|
+
|
90
|
+
def with_extra_fields(fields)
|
91
|
+
state[:extra_fields] = fields
|
92
|
+
yield
|
93
|
+
state[:extra_fields] = {}
|
94
|
+
end
|
95
|
+
|
96
|
+
def remove_invalid_fields(fields)
|
97
|
+
fields.delete_if do |_, v|
|
98
|
+
v.nil? || v.respond_to?(:empty?) && v.empty?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def log_data(_method_sym, message)
|
103
|
+
# merging is slow, we do not want to merge with empty hash if possible
|
104
|
+
fields_to_log = if state[:extra_fields].empty?
|
105
|
+
state[:base_fields]
|
106
|
+
else
|
107
|
+
state[:base_fields].merge(state[:extra_fields])
|
108
|
+
end
|
109
|
+
|
110
|
+
fields_to_log[MESSAGE] = message
|
111
|
+
fields_to_log[TIMESTAMP] = Time.now.utc.strftime(DATE_FORMAT)
|
112
|
+
|
113
|
+
@iodevice.write(Oj.dump(fields_to_log) + "\n")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Simple logger which tries to have an easy to see output.
|
118
|
+
class SimpleLogger < FastLogger
|
119
|
+
SEVERITY_TO_COLOR_MAP = {debug: '0;37', info: '0;37', warn: '33', error: '31', fatal: '31', unknown: '37'}
|
120
|
+
|
121
|
+
def log_data(method_sym, message)
|
122
|
+
color = SEVERITY_TO_COLOR_MAP[method_sym]
|
123
|
+
@iodevice.write("\033[#{color}m#{message}\033[0m\n")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
|
2
|
+
module Lorekeeper
|
3
|
+
# Allows to create a logger that will pass information to any logger registered
|
4
|
+
# It is useful so send the same message thought different loggers to different sinks
|
5
|
+
class MultiLogger
|
6
|
+
def initialize
|
7
|
+
@loggers = []
|
8
|
+
end
|
9
|
+
def add_logger(logger)
|
10
|
+
@loggers << logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(method, *args, &block)
|
14
|
+
result = @loggers.map do |logger|
|
15
|
+
logger.public_send(method, *args, &block) if logger.respond_to?(method)
|
16
|
+
end
|
17
|
+
# We call all the methods, delete nils and duplicates.
|
18
|
+
# Then hope for the best taking the first value
|
19
|
+
result.compact.uniq.first
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lorekeeper.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# The comment above will make all strings in a current file frozen
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'lorekeeper/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "lorekeeper"
|
9
|
+
spec.version = Lorekeeper::VERSION
|
10
|
+
spec.authors = ["Jordi Polo"]
|
11
|
+
spec.email = ["mumismo@gmail.com"]
|
12
|
+
|
13
|
+
spec.summary = %q{ Very fast JSON logger }
|
14
|
+
spec.description = %q{ Opinionated logger which outputs messages in JSON format }
|
15
|
+
spec.homepage = "http://www.gihub.com/jordipolo/lorekeeper"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency 'oj', '~> 2.14'
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "rspec", '~> 3.4'
|
28
|
+
spec.add_development_dependency "benchmark-ips", '~> 2.3'
|
29
|
+
spec.add_development_dependency "timecop", '~> 0.8'
|
30
|
+
spec.add_development_dependency "byebug", '~> 8.0'
|
31
|
+
spec.add_development_dependency "rbtrace", '~> 0.4'
|
32
|
+
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lorekeeper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jordi Polo
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: oj
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.14'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.4'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.4'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: benchmark-ips
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.3'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.3'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: timecop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.8'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.8'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: byebug
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '8.0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '8.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rbtrace
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.4'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.4'
|
125
|
+
description: " Opinionated logger which outputs messages in JSON format "
|
126
|
+
email:
|
127
|
+
- mumismo@gmail.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".rspec"
|
134
|
+
- ".travis.yml"
|
135
|
+
- Gemfile
|
136
|
+
- LICENSE.txt
|
137
|
+
- README.md
|
138
|
+
- Rakefile
|
139
|
+
- bin/console
|
140
|
+
- bin/setup
|
141
|
+
- lib/lorekeeper.rb
|
142
|
+
- lib/lorekeeper/fast_logger.rb
|
143
|
+
- lib/lorekeeper/json_logger.rb
|
144
|
+
- lib/lorekeeper/multi_logger.rb
|
145
|
+
- lib/lorekeeper/version.rb
|
146
|
+
- lorekeeper.gemspec
|
147
|
+
homepage: http://www.gihub.com/jordipolo/lorekeeper
|
148
|
+
licenses:
|
149
|
+
- MIT
|
150
|
+
metadata: {}
|
151
|
+
post_install_message:
|
152
|
+
rdoc_options: []
|
153
|
+
require_paths:
|
154
|
+
- lib
|
155
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
version: '0'
|
165
|
+
requirements: []
|
166
|
+
rubyforge_project:
|
167
|
+
rubygems_version: 2.5.1
|
168
|
+
signing_key:
|
169
|
+
specification_version: 4
|
170
|
+
summary: Very fast JSON logger
|
171
|
+
test_files: []
|