centralized_ruby_logger 0.0.1

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
+ 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: []