intake 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: febaaa600f3b7a5c8ed974a8e059a4d5ea12e61b0e5edf6fb0bf3c707f56027b
4
+ data.tar.gz: 9bc82ce4ad485486a397e63c84c7a54445df78b2e3f285b1d0ec26d1cfddfdc8
5
+ SHA512:
6
+ metadata.gz: bf360302e2ece8d18034a1b34587d3fa6c8a267f8d13ec64535b7de212e7307235b58b76a28c5f429fed832ee1ef4a1aa05c57391ba5cd74f98d207aa2c71033
7
+ data.tar.gz: d140b351c1171e9a5bce2e5e4d01926900300f60a8e18ce0c0c591cadcf54ac6ced6fa22b584cf3d8ad4dff754dfc31399613ba39a1b2a8a750869026c430ab1
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Andrey Maraev
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 all
13
+ 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 THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # intake
2
+
3
+ ## Description
4
+
5
+ **intake** is a powerful and easy to use logging library.
6
+ The library is designed with multiple base principles:
7
+
8
+ * Be a drop-in replacement for Ruby `Logger`
9
+ * Advanced API to support structured logging
10
+ * Highly efficient non-blocking logger API
11
+
12
+ ## Installation
13
+
14
+ ```shell
15
+ gem install intake
16
+ ```
17
+
18
+ ## License
19
+
20
+ The MIT License. See the [LICENSE](/LICENSE) file for the full text.
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'concurrent'
4
+ require 'immutable/deque'
5
+
6
+ module Intake
7
+ # Received events and asynchronously forward events to downstream sink
8
+ class AsyncSink
9
+ def initialize(forward_sink)
10
+ @forward_sink = forward_sink
11
+ @drain_buffer = Concurrent::AtomicReference.new
12
+ @drain_buffer.set(Immutable::Deque.empty)
13
+ @has_events_flag = Concurrent::Event.new
14
+ @drain_thread = Thread.new { drain_thread_func }
15
+ end
16
+
17
+ def receive(event)
18
+ @drain_buffer.update { |buffer| buffer.push(event) }
19
+ @has_events_flag.set
20
+ end
21
+
22
+ protected
23
+
24
+ def drain_thread_func
25
+ @has_events_flag.reset
26
+
27
+ loop do
28
+ @has_events_flag.wait(0.1)
29
+ @has_events_flag.reset
30
+
31
+ drain_backlog(snapshot_backlog)
32
+ end
33
+ end
34
+
35
+ def snapshot_backlog
36
+ backlog = nil
37
+ loop do
38
+ backlog = @drain_buffer.get
39
+ break if @drain_buffer.compare_and_set(backlog, Immutable::Deque.empty)
40
+ end
41
+ backlog
42
+ end
43
+
44
+ def drain_backlog(backlog)
45
+ until backlog.empty?
46
+ e = backlog.first
47
+ backlog = backlog.shift
48
+ @forward_sink.receive(e)
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ module Intake
6
+ # EventDrain is a single receiver of messages from loggers. EventDrain forward events to registered sinks
7
+ class EventDrain
8
+ include Singleton
9
+
10
+ def initialize
11
+ @sinks = []
12
+ end
13
+
14
+ def add_sink(sink)
15
+ @sinks << sink
16
+ end
17
+
18
+ def drain(event)
19
+ @sinks.each { |s| s.receive(event) }
20
+ end
21
+
22
+ def clear_sinks
23
+ @sinks.clear
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intake
4
+ # Filter is a proc-like object that filters events to be accepted by [Intake::Sink]
5
+ class Filter
6
+ # Applies filter to the event
7
+ # @param event [Intake::Event] event to filter
8
+ # @return [Boolean] true if [Intake::Sink] should accept the event; false otherwise
9
+ def call(_event)
10
+ true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../level'
4
+ require_relative '../filter'
5
+
6
+ module Intake
7
+ module Filters
8
+ # Filter by event level. Pass if event level is greater or equal to filter level.
9
+ class LevelFilter < Filter
10
+ # Initializes new instance of [Intake::Filters::LevelFilter]
11
+ # @param limit_level [Intake::Level|Symbol] filter level
12
+ def initialize(limit_level)
13
+ super()
14
+ @limit_level = Intake::Level[limit_level]
15
+ end
16
+
17
+ # Applies filter to the event
18
+ # @argument event [Intake::Event] event to test
19
+ # @return [Boolean] true if event pass the filter; false otherwise
20
+ def call(event)
21
+ event.level >= @limit_level
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../filter'
4
+
5
+ module Intake
6
+ module Filters
7
+ # Filter event by logger name. Pass if logger name starts with logger prefix.
8
+ class LoggerNamePrefixFilter < Intake::Filter
9
+ def initialize(prefix, include_root: true)
10
+ super()
11
+ @prefix = prefix
12
+ @include_root = include_root
13
+ end
14
+
15
+ def call(event)
16
+ name = event.logger_name
17
+ (@include_root && name == :root) || name.start_with?(@prefix)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intake
4
+ # Base class that serializes event to data format acceptable by sink (usually it's [String])
5
+ class Formatter
6
+ def initialize
7
+ @timestamp_format = '%Y-%m-%dT%H:%M:%S.%6N'
8
+ end
9
+
10
+ def call(event)
11
+ # rubocop:disable Layout/LineLength
12
+ "#{event.level.to_s[0]}, [#{event.timestamp.strftime(@timestamp_format)} ##{Process.pid}] #{event.level} -- #{event[:progname]}: #{event.message}\n"
13
+ # rubocop:enable Layout/LineLength
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'formatter'
4
+ require_relative 'sink'
5
+
6
+ module Intake
7
+ # Sink that writes log events to IO stream, e.g., STDOUT or file stream
8
+ class IOSink < Sink
9
+ def initialize(io)
10
+ super()
11
+ @io = io
12
+ @formatter = ::Intake::Formatter.new
13
+ end
14
+
15
+ attr_writer :formatter
16
+
17
+ def drain(event)
18
+ txt = @formatter.call(event)
19
+ @io.write(txt)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intake
4
+ # Log event level.
5
+ class Level
6
+ class << self
7
+ def []=(name, level)
8
+ (@s ||= {})[name] = level
9
+ end
10
+
11
+ def [](name)
12
+ (@s ||= {})[name]
13
+ end
14
+ end
15
+
16
+ attr_reader :name, :val
17
+
18
+ def initialize(name, val)
19
+ @val = val
20
+ @name = name
21
+ end
22
+
23
+ def to_s
24
+ @name.to_s.upcase
25
+ end
26
+
27
+ def <(other)
28
+ @val < other.val
29
+ end
30
+
31
+ def <=(other)
32
+ @val <= other.val
33
+ end
34
+
35
+ def >(other)
36
+ @val > other.val
37
+ end
38
+
39
+ def >=(other)
40
+ @val >= other.val
41
+ end
42
+
43
+ def ==(other)
44
+ @val == other.val
45
+ end
46
+
47
+ # Define Intake levels
48
+ [[:debug, 1000], [:info, 2000], [:warn, 3000], [:error, 4000], [:fatal, 5000]].each do |(n, v)|
49
+ ::Intake::Level[n] = ::Intake::Level.new(n, v).freeze
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intake
4
+ # Represents a log event.
5
+ class LogEvent
6
+ attr_reader :timestamp, :level, :logger_name, :message, :data
7
+
8
+ def initialize(timestamp, level, logger_name, msg, meta: nil)
9
+ @data = (meta || {}).freeze
10
+ @timestamp = timestamp
11
+ @level = level
12
+ @logger_name = logger_name
13
+ @message = msg
14
+ end
15
+
16
+ def [](key)
17
+ @data[key]
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ require_relative 'event_drain'
6
+ require_relative 'level'
7
+ require_relative 'log_event'
8
+ require_relative 'mdc'
9
+ require_relative 'repository'
10
+
11
+ module Intake
12
+ # Logger is a object that captures log event and forward that to event sinks.
13
+ class Logger
14
+ class << self
15
+ def [](name)
16
+ ::Intake::Repository.instance.get_or_add(name) do |logger_name|
17
+ Logger.new(logger_name)
18
+ end
19
+ end
20
+ end
21
+
22
+ attr_reader :name
23
+
24
+ def initialize(name)
25
+ validate_name(name)
26
+
27
+ @name = name
28
+ @level = ::Intake::Level[:info]
29
+ end
30
+
31
+ def level?(level)
32
+ @level.val <= level.val
33
+ end
34
+
35
+ def level=(level)
36
+ @level = case level
37
+ when String, Symbol then ::Intake::Level[level.to_sym]
38
+ when ::Intake::Level then level
39
+ end
40
+ end
41
+
42
+ %i[debug info warn error fatal].each do |level|
43
+ code = <<-CODE
44
+ undef :#{level} if method_defined? :#{level}
45
+ LEVEL_#{level} = ::Intake::Level[:#{level}]
46
+
47
+ def #{level}(msg = nil, meta: nil, error: nil, &block)
48
+ log_event(LEVEL_#{level}, msg, meta: meta, error: error, &block)
49
+ end
50
+ CODE
51
+ class_eval(code)
52
+ end
53
+
54
+ def log_event(level, msg = nil, meta: nil, error: nil)
55
+ return false unless level?(level)
56
+
57
+ msg = yield if msg.nil? && block_given?
58
+ meta ||= {}
59
+ meta[:error] = error unless error.nil?
60
+ meta.merge!(MDC.items) if MDC.any?
61
+ event = ::Intake::LogEvent.new(Time.now, level, @name, msg, meta: meta)
62
+ dispatch_event event
63
+ end
64
+
65
+ private
66
+
67
+ def validate_name(name)
68
+ case name
69
+ when String
70
+ raise ArgumentError, 'logger name must not be empty' if name.empty?
71
+ else
72
+ raise ArgumentError, 'logger name must be a string'
73
+ end
74
+ end
75
+
76
+ def dispatch_event(event)
77
+ EventDrain.instance.drain(event)
78
+ end
79
+ end
80
+ end
data/lib/intake/mdc.rb ADDED
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intake
4
+ # Mapped Diagnostic Context (MDC) is thread-aware Hash-like storage to add extra context details to logged events.
5
+ module MDC
6
+ SYNC_MUTEX = Mutex.new
7
+
8
+ class << self
9
+ def []=(key, value)
10
+ context[key] = value
11
+ end
12
+
13
+ def clear(key)
14
+ context.delete(key)
15
+ nil
16
+ end
17
+
18
+ def store(key, value)
19
+ MDC[key] = value
20
+ end
21
+
22
+ def any?
23
+ context.any?
24
+ end
25
+
26
+ def items
27
+ context.dup.freeze
28
+ end
29
+
30
+ private
31
+
32
+ def context
33
+ if Thread.current[:intake_mdc].nil?
34
+ SYNC_MUTEX.synchronize do
35
+ Thread.current[:intake_mdc] = {} if Thread.current[:intake_mdc].nil?
36
+ end
37
+ end
38
+ Thread.current[:intake_mdc]
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ module Intake
6
+ # Repository stores references to loggers by logger name.
7
+ class Repository
8
+ include Singleton
9
+
10
+ # Initializes new instance of [Intake] class.
11
+ def initialize
12
+ @store = {}
13
+ @mutex = Mutex.new
14
+ end
15
+
16
+ # Tests if logger with given name exists
17
+ # @return [Boolean] true if logger exists; false otherwise.
18
+ def key?(name)
19
+ @store.key? canonize_name(name)
20
+ end
21
+
22
+ def get_or_add(name)
23
+ name = canonize_name(name)
24
+ logger = @store[name]
25
+
26
+ if logger.nil?
27
+ logger = @mutex.synchronize do
28
+ @store[name] = yield(name) unless @store.key?(name)
29
+ @store[name]
30
+ end
31
+ end
32
+ logger
33
+ end
34
+
35
+ private
36
+
37
+ def canonize_name(name)
38
+ case name
39
+ when :root, 'root' then 'root'
40
+ when String then name
41
+ when Symbol then name.to_s
42
+ when Module then module_name(name)
43
+ when Object then module_name(name.class)
44
+ end
45
+ end
46
+
47
+ def module_name(mod)
48
+ mod.name
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ require_relative 'level'
6
+ require_relative 'logger'
7
+
8
+ module Intake
9
+ # Logger is a object that captures log event and forward that to event sinks.
10
+ class Logger
11
+ def as_ruby_logger(progname: nil)
12
+ RubyLoggerAdapter.new(self, progname)
13
+ end
14
+ end
15
+
16
+ # Adapter for [Intake::Logger] to match [::Logger] interface.
17
+ class RubyLoggerAdapter
18
+ [
19
+ [::Logger::DEBUG, ::Intake::Level[:debug]],
20
+ [::Logger::INFO, ::Intake::Level[:info]],
21
+ [::Logger::WARN, ::Intake::Level[:warn]],
22
+ [::Logger::ERROR, ::Intake::Level[:error]],
23
+ [::Logger::FATAL, ::Intake::Level[:fatal]],
24
+ [::Logger::UNKNOWN, ::Intake::Level[:fatal]]
25
+ ].each do |(n, v)|
26
+ ::Intake::Level[n] = v
27
+ end
28
+
29
+ %i[DEBUG INFO WARN ERROR FATAL UNKNOWN].each do |l|
30
+ code = <<-CODE
31
+ LEVEL_#{l} = ::Intake::Level[::Logger::Severity::#{l}]
32
+
33
+ def #{l.downcase}(progname = nil, &block)
34
+ log_event(LEVEL_#{l}, nil, progname, &block)
35
+ end
36
+ CODE
37
+ class_eval(code)
38
+ end
39
+
40
+ def initialize(logger, progname)
41
+ @progname = progname
42
+ @logger = logger
43
+ @meta = { progname: @progname }
44
+ end
45
+
46
+ def add(severity, message = nil, progname = nil, &block)
47
+ severity = ::Intake::Level[severity] unless severity.is_a? ::Intake::Level
48
+ log_event(severity, message, progname, &block)
49
+ end
50
+
51
+ private
52
+
53
+ def log_event(severity, message, progname, &block)
54
+ return true unless @logger.level?(severity)
55
+
56
+ progname = @progname if progname.nil?
57
+
58
+ if message.nil? && block.nil?
59
+ message = progname
60
+ progname = @progname
61
+ end
62
+
63
+ meta = progname == @progname ? @meta : { progname: progname }
64
+ @logger.log_event(severity, message, meta: meta, &block)
65
+ true
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'filter'
4
+
5
+ module Intake
6
+ # Sink receives log event and writes to a permanent storage.
7
+ class Sink
8
+ def initialize
9
+ @filters = []
10
+ end
11
+
12
+ def flush
13
+ @has_events_flag.set if @thread_model == :dedicated_thread
14
+ end
15
+
16
+ def receive(event)
17
+ return unless accept_event?(event)
18
+
19
+ drain event
20
+ end
21
+
22
+ def add_filter(filter)
23
+ @filters << filter
24
+ end
25
+
26
+ # Receives a message and write to a permanent storage
27
+ def drain(_event)
28
+ nil
29
+ end
30
+
31
+ protected
32
+
33
+ def accept_event?(event)
34
+ proceed = true
35
+ @filters.each do |f|
36
+ proceed &&= f.call(event)
37
+ break unless proceed
38
+ end
39
+ proceed
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Intake
4
+ VERSION = '0.1.0'
5
+ end
data/lib/intake.rb ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'intake/async_sink'
4
+ require_relative 'intake/io_sink'
5
+ require_relative 'intake/logger'
6
+ require_relative 'intake/version'
7
+ require_relative 'intake/filters/level_filter'
8
+ require_relative 'intake/filters/logger_name_prefix_filter'
9
+
10
+ # Public API module of intake logger
11
+ module Intake
12
+ def self.[](logger_name)
13
+ Intake::Logger[logger_name]
14
+ end
15
+
16
+ def self.add_sink(sink)
17
+ Intake::EventDrain.instance.add_sink sink
18
+ end
19
+
20
+ def self.clear_sinks
21
+ Intake::EventDrain.instance.clear_sinks
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,188 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: intake
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrey Maraev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-10-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: concurrent-ruby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: concurrent-ruby-ext
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.1.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.1.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: immutable-ruby
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.1.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.1.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: code-scanning-rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.6.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.6.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: debug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.6.0
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.6.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 13.0.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 13.0.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 3.11.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 3.11.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 1.36.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 1.36.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.21.2
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.21.2
139
+ description:
140
+ email:
141
+ - the_vk@thevk.net
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - LICENSE
147
+ - README.md
148
+ - lib/intake.rb
149
+ - lib/intake/async_sink.rb
150
+ - lib/intake/event_drain.rb
151
+ - lib/intake/filter.rb
152
+ - lib/intake/filters/level_filter.rb
153
+ - lib/intake/filters/logger_name_prefix_filter.rb
154
+ - lib/intake/formatter.rb
155
+ - lib/intake/io_sink.rb
156
+ - lib/intake/level.rb
157
+ - lib/intake/log_event.rb
158
+ - lib/intake/logger.rb
159
+ - lib/intake/mdc.rb
160
+ - lib/intake/repository.rb
161
+ - lib/intake/ruby_logger_adapter.rb
162
+ - lib/intake/sink.rb
163
+ - lib/intake/version.rb
164
+ homepage: https://github.com/the-vk/intake
165
+ licenses:
166
+ - MIT
167
+ metadata:
168
+ rubygems_mfa_required: 'true'
169
+ post_install_message:
170
+ rdoc_options: []
171
+ require_paths:
172
+ - lib
173
+ required_ruby_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - "~>"
176
+ - !ruby/object:Gem::Version
177
+ version: '3.0'
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ requirements: []
184
+ rubygems_version: 3.3.3
185
+ signing_key:
186
+ specification_version: 4
187
+ summary: Powerful and extensible logging library
188
+ test_files: []