centralized_ruby_logger 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 75e6fbe8d2a4f6b68f0c70654d7c99df4387f490
4
+ data.tar.gz: 28a4dc8fed04c9d34730d684d6e63ac7b2f3572b
5
+ SHA512:
6
+ metadata.gz: e326a5932c383d089f2486a16d42997414090f24d706efecdf37d1f1adadb7511199ada50bcc68462530f762522c1bc57ac348b5f5e77d566935cbf60bb75d85
7
+ data.tar.gz: 56e62926694b55c341cd807e448f3ad6445865f230e1ae71572a047c73359665a3fa706a91c741669e62240aa005e8334be05db7f2b07e081d5f5b6ef1291920
data/LICENCE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012-2016 Coralogix, Inc.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+
2
+ # Croalogix SDK - Ruby Implementation
3
+ This is an implementation of Coralogix Ruby SDK for Fluentd.
@@ -0,0 +1,87 @@
1
+ require_relative 'manager'
2
+ require_relative 'debug_logger'
3
+ require_relative 'httpsender'
4
+ require_relative 'constants'
5
+
6
+ module Coralogix
7
+ class CoralogixLogger
8
+ # Constructor.
9
+ #
10
+ # @param name - logger name.
11
+ def initialize private_key, app_name, sub_system_name, debug: false, type_name: "Centralized Ruby"
12
+ self.debug_mode=debug
13
+ @category = CORALOGIX_CATEGORY
14
+ @manager = LoggerManager.new
15
+ configure(private_key, app_name, sub_system_name, type_name)
16
+ end
17
+
18
+ # A getter for debug_mode.
19
+ # Default value is false.
20
+ # When set to true the coralogix logger will print output messages to a console and a file.
21
+ #
22
+ # @return [boolean] - true or false. (Default is false)
23
+ def debug_mode?
24
+ DebugLogger.debug_mode
25
+ end
26
+
27
+ # A setter for debug_mode.
28
+ # Default value is false.
29
+ # When set to true the coralogix logger will print output messages to a console and a file.
30
+ #
31
+ # @param value - true or false. (Default is false)
32
+ def debug_mode=(value)
33
+ DebugLogger.debug_mode=value
34
+ end
35
+
36
+ # A setter for disable_proxy.
37
+ # By default HTTP object will use proxy environment variable if exists. In some cases this migh be an issue
38
+ # When set to false the HTTP object will ignore any proxy.
39
+ #
40
+ # @param value - true or false. (Default is false)
41
+ def disable_proxy=(value)
42
+ @manager.disable_proxy=value
43
+ end
44
+
45
+ # Configure coralogix logger with customer specific values
46
+ #
47
+ # @param private_key - private key
48
+ # @param app_name - application name
49
+ # @param sub_system - sub system name
50
+ # @return [boolean] return a true or false.
51
+ def configure private_key, app_name, sub_system, type_name
52
+ private_key = (private_key.nil? || private_key.to_s.strip.empty?) ? FAILED_PRIVATE_KEY : private_key
53
+ app_name = (app_name.nil? || app_name.to_s.strip.empty?) ? NO_APP_NAME : app_name
54
+ sub_system = (sub_system.nil? || sub_system.to_s.strip.empty?) ? NO_SUB_SYSTEM : sub_system
55
+ @manager.set_logger_type_name type_name
56
+ @manager.configure(:privateKey => private_key, :applicationName => app_name, :subsystemName => sub_system) unless @manager.configured
57
+ end
58
+
59
+
60
+ # Flush all messages in buffer and send them immediately on the current thread.
61
+ def flush
62
+ @manager.flush
63
+ end
64
+
65
+ # Log a message.
66
+ #
67
+ # @param severity - log severity
68
+ # @param message - log message
69
+ # @param category - log category
70
+ # @param className - log class name
71
+ # @param methodName - log method name
72
+ # @param threadId - log thread id
73
+ def log severity, message, category: @category, className: "", methodName: "", threadId: Thread.current.object_id.to_s
74
+ @manager.add_logline message, severity, category, :className => className, :methodName => methodName, :threadId => threadId
75
+ end
76
+
77
+ # Create log methods for each severity.
78
+ # This is a ruby thing. If you are writing in other languages just create a method for each severity.
79
+ # For instance, for info severity it will create a method:
80
+ # def info message, category: @category, className: "", methodName: "", threadId: ""
81
+ SEVERITIES.keys.each do |severity|
82
+ define_method("#{severity}") do |message, category: @category, className: "", methodName: "", threadId: Thread.current.object_id.to_s|
83
+ @manager.add_logline message, SEVERITIES["#{__method__}".to_sym], category, :className => className, :methodName => methodName, :threadId => threadId
84
+ end
85
+ end
86
+ end
87
+ end
data/lib/constants.rb ADDED
@@ -0,0 +1,62 @@
1
+ module Coralogix
2
+
3
+ #Maximum log buffer size
4
+ MAX_LOG_BUFFER_SIZE = 12582912 #12mb
5
+
6
+ #Maximum chunk size
7
+ MAX_LOG_CHUNK_SIZE = 1572864 #1.5 mb
8
+
9
+ #Bulk send interval in normal mode.
10
+ NORMAL_SEND_SPEED_INTERVAL = 500.0 / 1000
11
+
12
+ #Bulk send interval in fast mode.
13
+ FAST_SEND_SPEED_INTERVAL = 100.0 / 1000
14
+
15
+ #Corologix severity mapper
16
+ SEVERITIES = {:debug => 1, :verbose => 2, :info => 3, :warning => 4, :error => 5, :critical => 6}
17
+
18
+
19
+ module Severity
20
+ DEBUG = 1
21
+ VERBOSE = 2
22
+ INFO = 3
23
+ WARNING = 4
24
+ ERROR = 5
25
+ CRITICAL = 6
26
+ end
27
+
28
+
29
+ #Coralogix logs url
30
+ CORALOGIX_LOG_URL = "https://api.coralogix.com:443/api/v1/logs"
31
+
32
+ #Coralogix time delat url
33
+ CORALOGIX_TIME_DELTA_URL = "https://api.coralogix.com:443/sdk/v1/time"
34
+
35
+ #Default private key
36
+ FAILED_PRIVATE_KEY = "9626c7dd-8174-5015-a3fe-5572e042b6d9"
37
+
38
+ #Default application name
39
+ NO_APP_NAME = "NO_APP_NAME"
40
+
41
+ #Default subsystem name
42
+ NO_SUB_SYSTEM = "NO_SUB_NAME"
43
+
44
+ #Default log file name
45
+ LOG_FILE_NAME = "coralogix.sdk.log"
46
+
47
+ #Default http timeout
48
+ HTTP_TIMEOUT = 30
49
+
50
+ #Number of attempts to retry http post
51
+ HTTP_SEND_RETRY_COUNT = 5
52
+
53
+ #Interval between failed http post requests
54
+ HTTP_SEND_RETRY_INTERVAL = 2
55
+
56
+ # Coralogix category
57
+ CORALOGIX_CATEGORY = 'CORALOGIX'
58
+
59
+ # Sync time update interval
60
+ SYNC_TIME_UPDATE_INTERVAL = 5 #minutes
61
+
62
+ end
@@ -0,0 +1,61 @@
1
+ require 'logger'
2
+
3
+ module Coralogix
4
+ # @private
5
+ class DebugLogger
6
+
7
+ def self.initialize
8
+ begin
9
+ @mutex = Mutex.new
10
+ @debug = false
11
+ rescue Exception => e
12
+ if @debug
13
+ puts e.message
14
+ puts e.backtrace.inspect
15
+ end
16
+ end
17
+ end
18
+
19
+ def self.debug_mode?
20
+ @debug
21
+ end
22
+
23
+ def self.debug_mode=(value)
24
+ begin
25
+ @debug = value
26
+ if value
27
+ @logger = Logger.new(LOG_FILE_NAME, 1, 10485760)
28
+ else
29
+ @logger.close unless @logger == nil
30
+ @logger = nil
31
+ end
32
+ rescue Exception => e
33
+ if @debug
34
+ puts e.message
35
+ puts e.backtrace.inspect
36
+ end
37
+ end
38
+ end
39
+
40
+ Logger::Severity.constants.each do |level|
41
+ define_singleton_method("#{level.downcase}") do |*args|
42
+ if @debug
43
+ @mutex.synchronize do
44
+ begin
45
+ puts "#{__method__.upcase}: #{Time.now.strftime('%H:%M:%S.%L')} - #{args}"
46
+ @logger.send("#{__method__}", args)
47
+ rescue Exception => e
48
+ puts e.message
49
+ puts e.backtrace.inspect
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+
57
+ initialize
58
+
59
+ end
60
+
61
+ end
data/lib/httpsender.rb ADDED
@@ -0,0 +1,101 @@
1
+ require 'net/http'
2
+ require 'json'
3
+ require_relative 'constants'
4
+ require_relative 'debug_logger'
5
+ require 'openssl'
6
+ require 'benchmark'
7
+ require 'date'
8
+ require 'time'
9
+
10
+ module Coralogix
11
+ # @private
12
+ class CoralogixHTTPSender
13
+ TICKS_IN_SECOND = 10**7
14
+ def disable_proxy value
15
+ @disable_proxy = value
16
+ end
17
+
18
+ def disable_proxy=(value)
19
+ @disable_proxy = value
20
+ end
21
+
22
+ def initialize
23
+ begin
24
+ @initialized = false
25
+ @mutex = Mutex.new
26
+ @uri = URI(CORALOGIX_LOG_URL)
27
+ if(@disable_proxy)
28
+ @http = Net::HTTP.new(@uri.host, @uri.port, p_addr=nil, p_port=nil)
29
+ else
30
+ @http = Net::HTTP.new(@uri.host, @uri.port)
31
+ end
32
+ @http.use_ssl = true
33
+ @http.keep_alive_timeout = 10
34
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
35
+ @http.read_timeout = HTTP_TIMEOUT # seconds
36
+ @http.open_timeout = HTTP_TIMEOUT # seconds
37
+ @req = Net::HTTP::Post.new(@uri.path, 'Content-Type' => 'application/json')
38
+ rescue Exception => e
39
+ DebugLogger.error e.message
40
+ DebugLogger.error e.backtrace.inspect
41
+ end
42
+ end
43
+
44
+ # A helper method to post http request
45
+ #
46
+ # @param bulk - JSON bulk containing the log entries
47
+ def send_request bulk
48
+ @mutex.synchronize do
49
+ attempt = 0
50
+ while attempt < HTTP_SEND_RETRY_COUNT
51
+ begin
52
+ DebugLogger.info "About to send bulk to Coralogix server. Attempt number: #{attempt+1}"
53
+ @req.body = bulk.to_json
54
+ DebugLogger.debug Benchmark.measure {
55
+ res = @http.request(@req)
56
+ DebugLogger.info "Successfully sent bulk to Coralogix server. Result is: #{res.code}"
57
+ }.to_s
58
+ return true
59
+ rescue Exception => e
60
+ DebugLogger.error e.message
61
+ DebugLogger.error e.backtrace.inspect
62
+ end
63
+ attempt+=1;
64
+ DebugLogger.error "Failed to send bulk. Will retry in: #{HTTP_SEND_RETRY_INTERVAL} seconds..."
65
+ sleep HTTP_SEND_RETRY_INTERVAL
66
+ end
67
+ end
68
+ end
69
+
70
+ # A helper method to get coralogix server current time and calculate the time difference
71
+ #
72
+ # @return [float] - time delta
73
+ def get_time_sync
74
+ @mutex.synchronize do
75
+ begin
76
+ DebugLogger.info "Syncing time with coralogix server"
77
+ res = @http.get(CORALOGIX_TIME_DELTA_URL)
78
+
79
+ if res.is_a?(Net::HTTPSuccess) && !res.body.to_s.empty?
80
+ #Get server ticks from 1970
81
+ server_ticks = res.body.to_i.to_s # Relative to 1970
82
+ #Take the first 13 digits
83
+ server_ticks = server_ticks[0..12]
84
+ #Convert the ticks to utc time
85
+ server_time = Time.parse(Time.at(server_ticks.to_i / 1000.to_f).strftime('%H:%M:%S.%L')).utc
86
+ local_time = Time.now.utc
87
+
88
+ time_delta = (server_time - local_time) * 1000.0
89
+ DebugLogger.info "Updating time delta to: #{time_delta}"
90
+ return true, time_delta
91
+ end
92
+ return false, 0
93
+ rescue Exception => e
94
+ DebugLogger.error e.message
95
+ DebugLogger.error e.backtrace.inspect
96
+ return false, 0
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
data/lib/manager.rb ADDED
@@ -0,0 +1,215 @@
1
+ require_relative 'httpsender'
2
+ require_relative 'constants'
3
+ require_relative 'debug_logger'
4
+ require 'date'
5
+ require 'time'
6
+
7
+ module Coralogix
8
+ # @private
9
+ class LoggerManager
10
+
11
+ attr_accessor :configured
12
+
13
+ def initialize
14
+ @logger_type = "Centralized Ruby"
15
+ @bulk_template = {:privateKey => FAILED_PRIVATE_KEY, :applicationName => NO_APP_NAME, :subsystemName => NO_SUB_SYSTEM}
16
+ @time_delta_last_update = 0
17
+ @time_delta = 0
18
+ @http_sender = CoralogixHTTPSender.new
19
+ @buffer = []
20
+ @buffer_size = 0
21
+ @mutex = Mutex.new
22
+ run
23
+ end
24
+
25
+ # Add a log line to our buffer.
26
+ #
27
+ # @param **args - Customer parameters:
28
+ # privateKey - Private Key
29
+ # applicationName - Application name
30
+ # subsystemName - Subsystem name
31
+ # @return [boolean] return true for success or false for failure.
32
+ def configure **args
33
+ begin
34
+ @bulk_template = args.merge({:computerName => `hostname`.strip})
35
+ DebugLogger.info "Successfully configured Coralogix logger."
36
+ @configured = true
37
+ add_logline "The Application Name #{@bulk_template[:applicationName]} and Subsystem Name #{@bulk_template[:subsystemName]} from the #{@logger_type} SDK, version #{version?} has started to send data.", Severity::INFO, CORALOGIX_CATEGORY
38
+ rescue Exception => e
39
+ DebugLogger.error e.message
40
+ DebugLogger.error e.backtrace.inspect
41
+ @configured = false
42
+ end
43
+ return @configured
44
+ end
45
+
46
+ def version?
47
+ begin
48
+ Gem.loaded_specs['coralogix_logger'].version.to_s
49
+ rescue Exception => e
50
+ DebugLogger.error e.message
51
+ DebugLogger.error e.backtrace.inspect
52
+ return '0.0.0'
53
+ end
54
+ end
55
+
56
+
57
+ # Add a log line to our buffer.
58
+ #
59
+ # @param message - The logs message. This is a must parameter.
60
+ # @param severity - The severity of the log message. This is a must parameter.
61
+ # @param category - The category (logger name) of the message. This is a must parameter.
62
+ # @param **args - Optional parameters. It can be:
63
+ # className - The class name where the log message was sent from.
64
+ # methodName - The method name where the log message was sent from.
65
+ # threadId - The thread id where the log message was sent from.
66
+ # @return [boolean] return true for success or false for failure.
67
+ def add_logline message, severity, category, **args
68
+ begin
69
+ @mutex.synchronize do
70
+ if @buffer_size < MAX_LOG_BUFFER_SIZE
71
+ #Validate message
72
+ message = (message.nil? || message.to_s.strip.empty?) ? "EMPTY_STRING" : msg2str(message)
73
+ #Validate severity
74
+ severity = (severity.nil? || severity.to_s < Severity::DEBUG.to_s || severity.to_s > Severity::CRITICAL.to_s) ? Severity::DEBUG : severity
75
+
76
+ #Validate category
77
+ category = (category.nil? || category.to_s.strip.empty?) ? CORALOGIX_CATEGORY : category.to_s
78
+
79
+ #Combine a logentry from the must parameters together with the optional one.
80
+ new_entry = {:text => message, :timestamp => Time.now.utc.to_f * 1000 + @time_delta, :severity => severity, :category => category}.merge(args)
81
+ @buffer << new_entry
82
+ #Update the buffer size to reflect the new size.
83
+ @buffer_size+=new_entry.to_json.bytesize
84
+ end
85
+ end
86
+ rescue Exception => e
87
+ DebugLogger.error e.message
88
+ DebugLogger.error e.backtrace.inspect
89
+ return false
90
+ end
91
+ return true
92
+ end
93
+
94
+ # Convert log message to string
95
+ # @param msg - log message to convert
96
+ #
97
+ # @return [String] return log message as string
98
+ def msg2str(msg)
99
+ begin
100
+ case msg
101
+ when ::String
102
+ msg
103
+ when ::Exception
104
+ "#{ msg.message } (#{ msg.class })\n" <<
105
+ (msg.backtrace || []).join("\n")
106
+ else
107
+ msg.inspect
108
+ end
109
+ rescue Exception => e
110
+ DebugLogger.error e.message
111
+ DebugLogger.error e.backtrace.inspect
112
+ return msg
113
+ end
114
+ end
115
+
116
+ # Flush all messages in buffer and send them immediately on the current thread.
117
+ def flush
118
+ send_bulk false
119
+ end
120
+
121
+ def set_logger_type_name name
122
+ @logger_type = name
123
+ end
124
+
125
+ # Send bulk from the buffer
126
+ def send_bulk time_sync=true
127
+ begin
128
+ update_time_delta_interval if time_sync
129
+ @mutex.synchronize do
130
+ # Total buffer size
131
+ size = @buffer.size
132
+ return unless size > 0
133
+
134
+ # If the size is bigger than the maximum allowed chunk size then split it by half.
135
+ # Keep splitting it until the size is less than MAX_LOG_CHUNK_SIZE
136
+ while (@buffer.take(size).join(",").bytesize > MAX_LOG_CHUNK_SIZE) || (size == 0)
137
+ size=size/2;
138
+ end
139
+
140
+ # We must take at leat one value. If the first message is bigger than MAX_LOG_CHUNK_SIZE
141
+ # we need to take it anyway.
142
+ size = size > 0 ? size : 1
143
+
144
+ DebugLogger.info "Checking buffer size. Total log entries is: #{size}"
145
+ @bulk_template[:logEntries] = @buffer.shift(size)
146
+
147
+ # Extract from the buffer size the total amount of the logs we removed from the buffer
148
+ @buffer_size-= (@bulk_template[:logEntries].to_json.bytesize - 2 - size-1)
149
+
150
+ # Make sure we are always positive
151
+ @buffer_size = @buffer_size >= 0 ? @buffer_size : 0
152
+
153
+ DebugLogger.info "Bufer size after removal is: #{@buffer.join(",").bytesize}"
154
+ end
155
+ @http_sender.send_request(@bulk_template) unless @bulk_template[:logEntries].empty?
156
+ rescue Exception => e
157
+ DebugLogger.error e.message
158
+ DebugLogger.error e.backtrace.inspect
159
+ end
160
+ end
161
+
162
+ # A setter for disable_proxy.
163
+ # By default HTTP object will use proxy environment variable if exists. In some cases this migh be an issue
164
+ # When set to false the HTTP object will ignore any proxy.
165
+ #
166
+ # @param value - true or false. (Default is false)
167
+ def disable_proxy=(value)
168
+ @http_sender.disable_proxy=value
169
+ end
170
+
171
+ # Sync log timestamps with coralogix server
172
+ def update_time_delta_interval
173
+ begin
174
+ #If more than 5 seconds passed from the last sync update
175
+ if ((DateTime.now.strftime('%Q').to_i - @time_delta_last_update) / 1000) >= (60 * SYNC_TIME_UPDATE_INTERVAL) #5 minuts
176
+ res, _time_delta = @http_sender.get_time_sync
177
+ if res
178
+ @time_delta = _time_delta
179
+ @time_delta_last_update = DateTime.now.strftime('%Q').to_i
180
+ end
181
+ end
182
+ rescue Exception => e
183
+ DebugLogger.error e.message
184
+ DebugLogger.error e.backtrace.inspect
185
+ end
186
+ end
187
+
188
+
189
+ # Start timer execution.
190
+ # The timer should send every X seconds logs from the buffer.
191
+ def run
192
+ begin
193
+ timer_thread = Thread.new do
194
+ while true
195
+ # Send log bulk
196
+ send_bulk
197
+
198
+ # Check when is the next time we should send logs?
199
+ # If we already have at least half of the max chunk size then we are working in fast mode
200
+ next_check_interval = @buffer_size > (MAX_LOG_CHUNK_SIZE / 2) ? FAST_SEND_SPEED_INTERVAL : NORMAL_SEND_SPEED_INTERVAL
201
+ DebugLogger.debug "Next buffer check is scheduled in #{next_check_interval} seconds"
202
+ sleep next_check_interval
203
+ end
204
+ end
205
+
206
+ #Set thread priority to a high number
207
+ timer_thread.priority = 100
208
+ rescue Exception => e
209
+ DebugLogger.error e.message
210
+ DebugLogger.error e.backtrace.inspect
211
+ return false
212
+ end
213
+ end
214
+ end
215
+ end
metadata ADDED
@@ -0,0 +1,50 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: centralized_ruby_logger
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Royee Goldberg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-17 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Coralogix Centralized Ruby Logger to send logs to Coralogix server.
14
+ email: royee@coralogix.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - LICENCE.txt
20
+ - README.md
21
+ - lib/centralized_ruby_logger.rb
22
+ - lib/constants.rb
23
+ - lib/debug_logger.rb
24
+ - lib/httpsender.rb
25
+ - lib/manager.rb
26
+ homepage: http://www.coralogix.com
27
+ licenses:
28
+ - MIT
29
+ metadata: {}
30
+ post_install_message:
31
+ rdoc_options: []
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: 2.0.0
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ requirements: []
45
+ rubyforge_project:
46
+ rubygems_version: 2.5.1
47
+ signing_key:
48
+ specification_version: 4
49
+ summary: Coralogix Centralized Ruby Logger SDK
50
+ test_files: []