log 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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