log 0.0.8

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.
@@ -0,0 +1,109 @@
1
+ # Author: Yaron Dror (yaron.dror.bb@gmail.com)
2
+ # Description: Implementation of the Log module - consumer\producer library.
3
+ # Note: The library could be enhance in the future due to project requirement (such as logging
4
+ # to mail, archives, remote servers etc)
5
+
6
+ require 'thread'
7
+ require 'params'
8
+
9
+ module BBFS
10
+
11
+ module Log
12
+ Params.float 'log_param_thread_sleep_time_in_seconds', 0.5 , \
13
+ 'log param. Thread sleep time in seconds'
14
+
15
+ # Base class for all consumers
16
+ # Child consumers must implement the 'consume' virtual method
17
+ class Consumer
18
+ # Initializes the consumer queue and starts a thread. The thread waits for data
19
+ # on the queue, and when data is popped, activates the virtual 'consume' method.
20
+ def initialize
21
+ @consumer_queue = Queue.new
22
+ Thread.new do
23
+ while (true)
24
+ consume @consumer_queue.pop
25
+ end
26
+ end
27
+ end
28
+
29
+ # push incoming data to the consumer queue
30
+ def push_data data
31
+ @consumer_queue.push data.clone
32
+ end
33
+ end
34
+
35
+ # BufferConsumerProducer acts as a consumer and as a producer.
36
+ # It has it's own consumers which are added to it.
37
+ # It saves all the data it consumes in a buffer which has a size and time limits.
38
+ # When one of the limits is exceeded, it flushes the buffer to it's own consumers
39
+ class BufferConsumerProducer < Consumer
40
+ def initialize buffer_size_in_mega_bytes, buffer_time_out_in_seconds
41
+ super()
42
+ @buffer_size_in_bytes = buffer_size_in_mega_bytes * 1000000
43
+ @buffer_time_out_in_seconds = buffer_time_out_in_seconds
44
+ @time_at_last_flush = Time.now.to_i
45
+ @buffer = []
46
+ @consumers = []
47
+ Thread.new do
48
+ while (true)
49
+ if @consumer_queue.empty? then
50
+ @consumer_queue.push nil
51
+ sleep Params['log_param_thread_sleep_time_in_seconds']
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ def add_consumer consumer
58
+ @consumers.push consumer
59
+ end
60
+
61
+ def consume data
62
+ @buffer.push data if not data.nil?
63
+ if (@buffer.inspect.size >= @buffer_size_in_bytes) or
64
+ ((Time.now.to_i - @time_at_last_flush) >= @buffer_time_out_in_seconds) then
65
+ flush_to_consumers
66
+ end
67
+ end
68
+
69
+ # flush the DB to the consumers
70
+ def flush_to_consumers
71
+ @consumers.each { |consumer| consumer.push_data @buffer}
72
+ @buffer.clear
73
+ @time_at_last_flush = Time.now.to_i
74
+ end
75
+ end
76
+
77
+ # The console consumer logs the data to the standard output
78
+ class ConsoleConsumer < Consumer
79
+ def consume data
80
+ puts data
81
+ end
82
+ end
83
+
84
+ # The file consumer logs the data to a file
85
+ class FileConsumer < Consumer
86
+ def initialize file_name
87
+ super()
88
+ @file_name = file_name
89
+ if File.exist? @file_name then
90
+ File.delete @file_name
91
+ end
92
+ end
93
+
94
+ def consume data
95
+ begin
96
+ file_handler = File.new @file_name, 'a'
97
+ file_handler.puts data
98
+ rescue
99
+ Exception
100
+ puts "Failed to open log file:#{@file_name}"
101
+ puts $!.class
102
+ puts $!
103
+ ensure
104
+ file_handler.close
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,5 @@
1
+ module BBFS
2
+ module Log
3
+ VERSION = "0.0.8"
4
+ end
5
+ end
data/lib/log.rb ADDED
@@ -0,0 +1,130 @@
1
+ # Author: Yaron Dror (yaron.dror.bb@gmail.com)
2
+ # Description: The file contains the code which implements the 'Log' module
3
+ # Run: Add to 'require' list.
4
+ # Note: The logger will be automatically initialized if log_param_auto_start is true
5
+ # If log_param_auto_start is false then 'Log.init' method will be called
6
+ # on the first attempt to log.
7
+
8
+ require 'params'
9
+ require 'thread'
10
+ require 'log/log_consumer.rb'
11
+
12
+ module BBFS
13
+ # Module: Log.
14
+ # Abstruct: The Log is used to log info\warning\error\debug messages
15
+ # Note: The logger will be automatically initialized if log_param_auto_start is true
16
+ # If log_param_auto_start is false then 'Log.init' method will be called
17
+ # on the first attempt to log.
18
+ module Log
19
+ #Auxiliary method to retrieve the executable name
20
+ def Log.executable_name
21
+ /([a-zA-Z0-9\-_\.]+):\d+/ =~ caller[caller.size-1]
22
+ return $1
23
+ end
24
+
25
+ # Global params
26
+ Params.boolean 'log_param_auto_start',false, \
27
+ 'log param. If true, log will start automatically. ' + \
28
+ 'Else, init should be called. ' + \
29
+ 'Else Init will be called automatically on the first attempt to log.'
30
+ Params.integer 'log_debug_level', 0 , 'Log level.'
31
+ Params.integer 'log_param_number_of_mega_bytes_stored_before_flush', 0, \
32
+ 'log param. Number of mega bytes stored before they are flushed.'
33
+ Params.float 'log_param_max_elapsed_time_in_seconds_from_last_flush', 0, \
34
+ 'log param. Max elapsed time in seconds from last flush'
35
+ Params.boolean 'log_write_to_file', true , \
36
+ 'If true then the logger will write the messages to a file.'
37
+ Params.boolean 'log_write_to_console', false , \
38
+ 'If true then the logger will write the messages to the console.'
39
+ Params.string 'log_file_name', File.expand_path("~/.bbfs/log/#{Log.executable_name}.log") , \
40
+ 'Default log file name: ~/.bbfs/log/<executable_name>.log'
41
+
42
+ @consumers = []
43
+ @log_initialized = false
44
+
45
+ #Note that the logger will be automatically initialized if log_param_auto_start is true
46
+ if Params['log_param_auto_start'] then
47
+ Log.init
48
+ end
49
+
50
+ # Init the Log consumers
51
+ def Log.init
52
+ Log.clear_consumers
53
+ # Console - If enabled, will flush the log immediately to the console
54
+ if Params['log_write_to_console'] then
55
+ console_consumer = ConsoleConsumer.new
56
+ @consumers.push console_consumer
57
+ end
58
+ # BufferConsumerProducer - If enabled, will use the file consumer to flush a buffer to a file
59
+ if Params['log_write_to_file'] then
60
+ file_consumer = FileConsumer.new Params['log_file_name']
61
+ buffer_consumer_producer = BufferConsumerProducer.new \
62
+ Params['log_param_number_of_mega_bytes_stored_before_flush'], \
63
+ Params['log_param_max_elapsed_time_in_seconds_from_last_flush']
64
+ buffer_consumer_producer.add_consumer file_consumer
65
+ @consumers.push buffer_consumer_producer
66
+ end
67
+ @log_initialized = true
68
+ Log.info 'BBFS Log initialized.' # log first data
69
+ Log.info "Log file path:'#{Params['log_file_name']}'" if Params['log_write_to_file']
70
+ Params.get_init_messages().each { |msg|
71
+ Log.info msg
72
+ } unless Params.get_init_messages().empty?
73
+ end
74
+
75
+ # Clears consumers
76
+ def Log.clear_consumers
77
+ @consumers.clear
78
+ end
79
+
80
+ # Adding consumer to the logger
81
+ def Log.add_consumer consumer
82
+ @consumers.push consumer
83
+ end
84
+
85
+ # formatting the data and push to consumers
86
+ def Log.basic msg, type
87
+ Log.init if not @log_initialized
88
+ /([a-zA-Z0-9\-_\.]+:\d+)/ =~ caller[1]
89
+ data = "[BBFS LOG] [#{Time.now()}] [#{type}] [#{$1}] [#{msg}]"
90
+ @consumers.each { |consumer| consumer.push_data data }
91
+ end
92
+
93
+ # Log warning massages
94
+ def Log.warning msg
95
+ Log.basic msg, 'WARNING'
96
+ end
97
+
98
+ # Log error massages
99
+ def Log.error msg
100
+ Log.basic msg, 'ERROR'
101
+ end
102
+
103
+ # Log info massages
104
+ def Log.info msg
105
+ Log.basic msg, 'INFO'
106
+ end
107
+
108
+ # Log debug level 1 massages
109
+ def Log.debug1 msg
110
+ if Params['log_debug_level'] > 0 then
111
+ Log.basic msg, 'DEBUG-1'
112
+ end
113
+ end
114
+
115
+ # Log debug level 2 massages
116
+ def Log.debug2 msg
117
+ if Params['log_debug_level'] > 1 then
118
+ Log.basic msg, 'DEBUG-2'
119
+ end
120
+ end
121
+
122
+ # Log debug level 3 massages
123
+ def Log.debug3 msg
124
+ if Params['log_debug_level'] > 2 then
125
+ Log.basic msg, 'DEBUG-3'
126
+ end
127
+ end
128
+
129
+ end
130
+ end
@@ -0,0 +1,165 @@
1
+ # Author: Yaron Dror (yaron.dror.bb@gmail.com)
2
+ # Description: Log test file.
3
+ # run: rake test.
4
+ # Note: This file will be tested along with all project tests.
5
+
6
+ require 'params'
7
+ require 'test/unit'
8
+ require_relative '../../lib/log.rb'
9
+ require_relative '../../lib/log/log_consumer.rb'
10
+
11
+ module BBFS
12
+
13
+ module Log
14
+ # Creating a test consumer class to be able to read the data pushed
15
+ # to the consumer by the logger
16
+ class TestConsumer < Consumer
17
+ attr_reader :test_queue
18
+
19
+ def initialize
20
+ super
21
+ @test_queue = Queue.new()
22
+ end
23
+
24
+ def consume data
25
+ @test_queue.push data
26
+ end
27
+ end
28
+
29
+ class TestLog < Test::Unit::TestCase
30
+
31
+ LOG_TEST_FILE_NAME = 'log_test.rb:'
32
+ LOG_PREFIX = 'BBFS LOG'
33
+
34
+ def initialize name
35
+ super
36
+ Params['log_write_to_console'] = false
37
+ Params['log_write_to_file'] = false
38
+ Log.init
39
+ @test_consumer = TestConsumer.new
40
+ Log.add_consumer @test_consumer
41
+ @line_regexp = Regexp.new(/\[(.*)\] \[(.*)\] \[(.*)\] \[(.*)\] \[(.*)\]/)
42
+ end
43
+
44
+ #check expected format: [LOG_PREFIX] [Time] [INFO] [FILE_NAME:LINE] [MESSAGE]
45
+ def assert_message line, time, type, file_line, msg
46
+ format_containers = @line_regexp.match(line)
47
+ assert_equal format_containers.captures.size, 5
48
+ if format_containers.captures.size == 5 then
49
+ assert_equal format_containers.captures[0], LOG_PREFIX
50
+ assert_equal format_containers.captures[1], time.to_s
51
+ assert_equal format_containers.captures[2], type
52
+ assert_equal format_containers.captures[3], file_line
53
+ assert_equal format_containers.captures[4], msg
54
+ end
55
+ end
56
+
57
+ def test_check_info_format
58
+ #set test phase
59
+ test_message = 'This is a test INFO message.'
60
+ testTime = Time.now
61
+ Log.info test_message
62
+ line = __LINE__ - 1
63
+ #check test phase
64
+ pop_message = @test_consumer.test_queue.pop
65
+ assert_message pop_message, testTime, 'INFO', LOG_TEST_FILE_NAME + line.to_s, test_message
66
+ end
67
+
68
+ def test_check_warning_format
69
+ #set test phase
70
+ test_message = 'This is a test WARNING message.'
71
+ testTime = Time.now
72
+ Log.warning test_message
73
+ line = __LINE__ - 1
74
+
75
+ #check test phase
76
+ pop_message = @test_consumer.test_queue.pop
77
+ assert_message pop_message, testTime, 'WARNING', LOG_TEST_FILE_NAME + line.to_s, test_message
78
+ end
79
+
80
+ def test_check_error_format
81
+ #set test phase
82
+ test_message = 'This is a test ERROR message.'
83
+ testTime = Time.now
84
+ Log.error test_message
85
+ line = __LINE__ - 1
86
+
87
+ #check test phase
88
+ pop_message = @test_consumer.test_queue.pop
89
+ assert_message pop_message, testTime, 'ERROR', LOG_TEST_FILE_NAME + line.to_s, test_message
90
+ end
91
+
92
+ def test_check_debug_level_0
93
+ #set test phase
94
+ Params['log_debug_level'] = 0
95
+ Log.debug1 'This is a test debug-1 message.'
96
+ Log.debug2 'This is a test debug-2 message.'
97
+ Log.debug3 'This is a test debug-3 message.'
98
+ #check test phase
99
+ queue_size = @test_consumer.test_queue.size
100
+ assert_equal queue_size, 0 , \
101
+ "At debug level 0, no debug messages should be found.Test found:#{queue_size} messages."
102
+ end
103
+
104
+ def test_check_debug_level_1
105
+ #set test phase
106
+ Params['log_debug_level'] = 1
107
+ test_message_1 = 'This is a test DEBUG-1 message.'
108
+ test_message_2 = 'This is a test DEBUG-2 message.'
109
+ test_message_3 = 'This is a test DEBUG-3 message.'
110
+ testTime = Time.now
111
+ Log.debug1 test_message_1
112
+ line = __LINE__ - 1
113
+ Log.debug2 test_message_2
114
+ Log.debug3 test_message_3
115
+
116
+ #check test phase
117
+ pop_message = @test_consumer.test_queue.pop
118
+ assert_message pop_message, testTime, 'DEBUG-1', LOG_TEST_FILE_NAME + line.to_s, test_message_1
119
+ end
120
+
121
+ def test_check_debug_level_2
122
+ #set test phase
123
+ Params['log_debug_level'] = 2
124
+ test_message_1 = 'This is a test DEBUG-1 message.'
125
+ test_message_2 = 'This is a test DEBUG-2 message.'
126
+ test_message_3 = 'This is a test DEBUG-3 message.'
127
+ testTime = Time.now
128
+ Log.debug1 test_message_1
129
+ line_1 = __LINE__ - 1
130
+ Log.debug2 test_message_2
131
+ line_2 = __LINE__ - 1
132
+ Log.debug3 test_message_3
133
+
134
+ #check test phase
135
+ pop_message = @test_consumer.test_queue.pop
136
+ assert_message pop_message, testTime, 'DEBUG-1', LOG_TEST_FILE_NAME + line_1.to_s, test_message_1
137
+ pop_message = @test_consumer.test_queue.pop
138
+ assert_message pop_message, testTime, 'DEBUG-2', LOG_TEST_FILE_NAME + line_2.to_s, test_message_2
139
+ end
140
+
141
+ def test_check_debug_level_3
142
+ #set test phase
143
+ Params['log_debug_level'] = 3
144
+ test_message_1 = 'This is a test DEBUG-1 message.'
145
+ test_message_2 = 'This is a test DEBUG-2 message.'
146
+ test_message_3 = 'This is a test DEBUG-3 message.'
147
+ testTime = Time.now
148
+ Log.debug1 'This is a test DEBUG-1 message.'
149
+ line_1 = __LINE__ - 1
150
+ Log.debug2 'This is a test DEBUG-2 message.'
151
+ line_2 = __LINE__ - 1
152
+ Log.debug3 'This is a test DEBUG-3 message.'
153
+ line_3 = __LINE__ - 1
154
+
155
+ #check test phase
156
+ pop_message = @test_consumer.test_queue.pop
157
+ assert_message pop_message, testTime, 'DEBUG-1', LOG_TEST_FILE_NAME + line_1.to_s, test_message_1
158
+ pop_message = @test_consumer.test_queue.pop
159
+ assert_message pop_message, testTime, 'DEBUG-2', LOG_TEST_FILE_NAME + line_2.to_s, test_message_2
160
+ pop_message = @test_consumer.test_queue.pop
161
+ assert_message pop_message, testTime, 'DEBUG-3', LOG_TEST_FILE_NAME + line_3.to_s, test_message_3
162
+ end
163
+ end
164
+ end
165
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: log
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.8
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Yaron Dror
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: params
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: logging data to file, console etc. Data can be pushed using info\warning\error\debug-levels
31
+ categories
32
+ email: yaron.dror.bb@gmail.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - lib/log.rb
38
+ - lib/log/log_consumer.rb
39
+ - lib/log/version.rb
40
+ - test/log/log_test.rb
41
+ homepage: http://github.com/yarondbb/bbfs
42
+ licenses: []
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ none: false
49
+ requirements:
50
+ - - ! '>='
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubyforge_project:
61
+ rubygems_version: 1.8.23
62
+ signing_key:
63
+ specification_version: 3
64
+ summary: Library for logging data.
65
+ test_files:
66
+ - test/log/log_test.rb