em-syslog-logger 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,220 +1,29 @@
1
1
 
2
2
  require 'socket'
3
- require 'rubygems'
4
3
  require 'eventmachine'
4
+ require 'em-syslog/syslog.rb'
5
+ require 'em-syslog/connection_tcp.rb'
6
+ require 'em-syslog/connection_udp.rb'
7
+ require 'em-syslog/connection_unix.rb'
8
+ require 'em-syslog/logger.rb'
5
9
 
6
10
  module EventMachine
7
11
  module Syslog
8
- # THIEVERY: http://github.com/kpumuk/ruby_syslog
9
- SEVERITIES = {
10
- :emergency => 0, # system is unusable
11
- :alert => 1, # action must be taken immediately
12
- :critical => 2, # critical conditions
13
- :error => 3, # error conditions
14
- :warning => 4, # warning conditions
15
- :notice => 5, # normal but significant condition
16
- :informational => 6, # informational messages
17
- :info => 6, # informational messages (short name for the previous)
18
- :debug => 7 # debug-level messages
19
- }
20
- # THIEVERY: http://github.com/kpumuk/ruby_syslog
21
- FACILITIES = {
22
- :kernel => 0, # kernel messages
23
- :user_level => 1, # user-level messages
24
- :mail => 2, # mail system
25
- :daemons => 3, # system daemons
26
- :security => 4, # security/authorization messages
27
- :internal => 5, # messages generated internally by syslogd
28
- :printer => 6, # line printer subsystem
29
- :network => 7, # network news subsystem
30
- :uucp => 8, # UUCP subsystem
31
- :clock => 9, # clock daemon
32
- :security1 => 10, # security/authorization messages
33
- :ftp => 11, # FTP daemon
34
- :ntp => 12, # NTP subsystem
35
- :log_audit => 13, # log audit
36
- :log_alert => 14, # log alert
37
- :clock1 => 15, # clock daemon
38
- :local0 => 16, # local use 0
39
- :local1 => 17, # local use 1
40
- :local2 => 18, # local use 2
41
- :local3 => 19, # local use 3
42
- :local4 => 20, # local use 4
43
- :local5 => 21, # local use 5
44
- :local6 => 22, # local use 6
45
- :local7 => 23 # local use 7
46
- }
12
+ ##
13
+ # Candy for creating a new Logger object or returned a cached one
47
14
 
48
15
  def self.logger( *a)
49
16
  EventMachine::Logger.new( *a)
50
17
  end
51
-
52
- module ConnectionUDP
53
- # EM does not support doing UDP over unix domain sockets, so we have to manually handle it.
54
- def self.create_unix
55
- ::Socket.new(
56
- ::Socket::PF_UNIX,
57
- ::Socket::SOCK_DGRAM
58
- )
59
- end
60
-
61
- def self.pack_unix( path)
62
- ::Socket.pack_sockaddr_un( path)
63
- end
64
-
65
- def setup( host, port, unix_connection=nil)
66
- @host = unix_connection.nil? ? host : ::Socket.pack_sockaddr_un( host)
67
- @port = port
68
- @unix_connection = unix_connection
69
- @unix_connection.connect( @host) unless @unix_connection.nil?
70
- end
71
-
72
- # Should not be needed
73
- def notify_readable
74
- read_packet
75
- end
76
-
77
- def read_packet
78
- data, sender = @unix_connection.recvfrom( 1024)
79
- true
80
- end
81
-
82
- def send_msg( msg)
83
- if @unix_connection.nil?
84
- send_datagram( msg, @host, @port)
85
- else
86
- @unix_connection.send( msg, 0)
87
- end
88
- end
89
- end
90
-
91
- module ConnectionTCP
92
- def setup( host, port)
93
- @host = host
94
- @port = port
95
- @queue = Array.new
96
- @connected = false
97
- end
98
-
99
- def post_init
100
- @connected = true
101
- @queue.size.times {
102
- send_msg( @queue.shift)
103
- }
104
- end
105
-
106
- def send_msg( msg)
107
- if @connected
108
- send_data( msg)
109
- else
110
- @queue.push( msg)
111
- end
112
- end
113
-
114
- def unbind
115
- @connected = false
116
- reconnect( @host, @port)
117
- end
118
- end
119
- end
120
-
121
- class Logger
122
- @@connection_cache = Hash.new
123
- attr_reader :idenity, :resource
124
-
125
- # Yup hack new class method for cache candy
126
- def self.new( idenity, resource="unix://dev/log")
127
- # See if we have a connection already in our cache
128
- key = self.mk_cache_index_key( idenity, resource)
129
- return @@connection_cache[key] if @@connection_cache.has_key? key and @@connection_cache[key].error? == false
130
-
131
- # Otherwise allocate a new object to do the work
132
- instance = self.allocate
133
- instance.send( :initialize, idenity, resource)
134
- @@connection_cache[key] = instance
135
- end
136
-
137
- def initialize( idenity, resource)
138
- @idenity = idenity.to_s + "[" + Process.pid.to_s + "]"
139
- @resource = resource
140
- resource = self.class.parse_resource( resource)
141
-
142
- case resource[0]
143
- when :unix
144
- # need better checking here
145
- raise "unix domain socket #{resource[1]} does not exist!" unless ::File.exists?( resource[1])
146
- @connection = Syslog::ConnectionUDP.create_unix
147
- resource << @connection
148
- @connection = EM.watch( @connection, Syslog::ConnectionUDP)
149
- when :tcp
150
- @connection = EM.connect( resource[1], resource[2], Syslog::ConnectionTCP)
151
- else
152
- @connection = EM.open_datagram_socket( '0.0.0.0', 0, Syslog::ConnectionUDP)
153
- end
154
- raise "unable to create connection" if @connection.nil?
155
- resource.shift
156
- @connection.setup( *resource)
157
- end
158
-
159
- def log( msg, facility, severity, debug=true)
160
- m = String.new
161
- if debug
162
- raise "Invalid log severity!" unless Syslog::SEVERITIES.has_key? severity
163
- raise "Invalid log facility!" unless Syslog::FACILITIES.has_key? facility
164
- end
165
- m += "<" + self.class.class_variable_get("@@syskey_#{facility}_#{severity}".to_sym).to_s + ">"
166
- m += self.class.timestamp + " " + ::Socket.gethostname + " #{@idenity} " + msg.to_s
167
- @connection.send_msg( m)
168
- end
169
-
170
- #Meta program our facility/severity keys and methods
171
- Syslog::FACILITIES.each {|facility,facility_int|
172
- Syslog::SEVERITIES.each {|severity,severity_int|
173
- define_method( "#{facility}_#{severity}".to_sym) do |msg|
174
- log( msg, facility, severity, false)
175
- end
176
- self.class_variable_set("@@syskey_#{facility}_#{severity}".to_sym, (facility_int * 8 + severity_int))
177
- }
178
- }
179
-
180
- private
181
- def self.timestamp( time=Time.now)
182
- day = time.strftime("%d")
183
- day = day.sub(/^0/, ' ') if day =~ /^0\d/
184
- time.strftime("%b #{day} %H:%M:%S")
185
- end
186
-
187
- # Likely not the fastest and best way to make a cache index
188
- def self.mk_cache_index_key( idenity, resource)
189
- idenity.to_s + resource.split(':').each {|i| i.gsub(/\./,'') }.join
190
- end
191
-
192
- def self.parse_resource( resource)
193
- split_point = resource.index(':')
194
- answer = [ resource[0..(split_point-1)].to_sym, resource[(split_point+1)..-1]]
195
- split_point = answer[1].index(':')
196
- if split_point.nil? == false and split_point > 0
197
- answer << answer[1][(split_point+1)..-1].to_i
198
- answer[1] = answer[1][0..(split_point-1)]
199
- elsif split_point.nil? and answer[0] != :unix
200
- answer << 514
201
- elsif split_point.nil? == false
202
- raise "Resource parse error"
203
- else
204
- answer[1].slice!(0)
205
- answer << nil
206
- end
207
- answer
208
- end
209
18
  end
210
- end
19
+ end
211
20
 
212
21
  if __FILE__ == $0
213
22
  EM.run {
214
23
  EM.kqueue if EM.kqueue?
215
24
  EM.epoll if EM.epoll?
216
25
 
217
- logger = EM::Syslog.logger( "em-syslog-test")
26
+ logger = EM::Syslog.logger( {:idenity => "em-syslog-test" })
218
27
  EM.next_tick {
219
28
  logger.log( "TEST INFO", :daemons, :info)
220
29
  logger.mail_error( "MAIL ERROR")
@@ -222,3 +31,5 @@ if __FILE__ == $0
222
31
  }
223
32
  end
224
33
 
34
+ require 'em-syslog/version.rb'
35
+
@@ -0,0 +1,84 @@
1
+
2
+ module EventMachine
3
+ module Syslog
4
+ ##
5
+ # Our module to pass to EventMachine to create the connection handler
6
+
7
+ module ConnectionTCP
8
+ DEFAULTS = {:queue_max_size => 500,
9
+ :queue_batch_send => 20,
10
+ :on_hangup => nil,
11
+ :reconnect => true
12
+ }
13
+ ##
14
+ # setup our connection with remote/local information, with a hash config merged against ConnectionTCP::DEFAULTS
15
+
16
+ def setup( host, port, config={})
17
+ config = DEFAULTS.merge( config)
18
+ @host = host
19
+ @port = port
20
+ @do_reconnect = config[:on_hangup]
21
+ @reconnect = config[:reconnect]
22
+ @queue = Array.new
23
+ @connected = false
24
+ true
25
+ end
26
+
27
+ ##
28
+ # we got our connection, time to start sending any items we have queued up
29
+
30
+ def post_init
31
+ @connected = true
32
+ queue_send_batch
33
+ end
34
+
35
+ ##
36
+ # queue messages if we are not connected.
37
+
38
+ def send_msg( msg)
39
+ if @connected
40
+ send_data( msg)
41
+ else
42
+ queue_push( msg)
43
+ end
44
+ end
45
+
46
+ ##
47
+ # Do you want to be told when it disconnects and/or do you want to reconnect right away config[:reconnect] = true
48
+ # passing config[:on_hangup] provide a proc.
49
+
50
+ def unbind
51
+ @connected = false
52
+ reconnect( @host, @port) if @do_reconnect
53
+ @on_hangup.call unless @on_hangup.nil?
54
+ end
55
+
56
+ private
57
+ ##
58
+ # Rotate out old messages for newer messages.
59
+
60
+ def queue_push( msg)
61
+ old_message = (@queue.length >= @queue_max_size) ? @queue.shift : nil
62
+ @queue << msg
63
+ old_message
64
+ end
65
+
66
+ ##
67
+ # loop batch send on each tick sending at least config[:queue_batch_size] times
68
+
69
+ def queue_send_batch
70
+ run_list = @queue.slice!(0..@queue_batch_size)
71
+ run_list.each {|msg|
72
+ send_msg( msg)
73
+ }
74
+ unless @queue.empty?
75
+ EM.next_tick {
76
+ queue_send_batch
77
+ }
78
+ end
79
+ true
80
+ end
81
+ end
82
+ end
83
+ end
84
+
@@ -0,0 +1,37 @@
1
+
2
+ module EventMachine
3
+ module Syslog
4
+ ##
5
+ # Our module to pass to EventMachine to handle the UDP Connection over IP Socket
6
+
7
+ module ConnectionUDP
8
+
9
+ def setup( host, port)
10
+ @host = host
11
+ @port = port
12
+ end
13
+
14
+ ##
15
+ # Should not be needed
16
+
17
+ def notify_readable
18
+ read_packet
19
+ end
20
+
21
+ ##
22
+ # Should not be needed
23
+
24
+ def read_packet
25
+ data, sender = @unix_connection.recvfrom( 1024)
26
+ true
27
+ end
28
+
29
+ ##
30
+ # Handle no buffering just send it
31
+
32
+ def send_msg( msg)
33
+ send_datagram( msg, @host, @port)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,41 @@
1
+
2
+ module EventMachine
3
+ module Syslog
4
+ module ConnectionUDP
5
+ ##
6
+ # Our module to pass to EventMachine to handle the UDP Connection over IPC Socket
7
+
8
+ module UNIX
9
+ include ConnectionUDP
10
+ ##
11
+ # we also have to code around the difference of Socket.new in ruby 1.8 and 1.9
12
+
13
+ def self.create_unix
14
+ case RUBY_VERSION.split('.')[1].to_i
15
+ when 8
16
+ ::Socket.new(
17
+ ::Socket::PF_UNIX,
18
+ ::Socket::SOCK_DGRAM,
19
+ 0
20
+ )
21
+ else
22
+ ::Socket.new(
23
+ ::Socket::PF_UNIX,
24
+ ::Socket::SOCK_DGRAM
25
+ )
26
+ end
27
+ end
28
+
29
+ def setup( ipc, path)
30
+ ipc_address = ::Socket.pack_sockaddr_un( path)
31
+ @unix_connection = ipc
32
+ @unix_connection.connect( ipc_address)
33
+ end
34
+
35
+ def send_msg( msg)
36
+ @unix_connection.send( msg, 0)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,150 @@
1
+
2
+ module EventMachine
3
+ ##
4
+ # Generic Logger Class, providing simple to use statements
5
+ # auto fills in the most likely config DEFAULTS
6
+
7
+ class Logger
8
+ @@connection_cache = Hash.new
9
+ begin
10
+ @@hostname = ::Socket.gethostname.split('.')[0]
11
+ rescue Exception
12
+ @@hostname = 'localhost'
13
+ end
14
+ attr_reader :idenity, :resource, :include_hostname
15
+ DEFAULTS = {:idenity => $PROGRAM_NAME,
16
+ :include_hostname => false,
17
+ :resource => "udp:/dev/log"
18
+ }
19
+ ##
20
+ # hack new class method for caching connections, making it safe to keep variables out of scope.
21
+
22
+ def self.new( config = {})
23
+ config = DEFAULTS.merge config
24
+ # See if we have a connection already in our cache
25
+ key = self.mk_cache_index_key( config[:idenity], config[:resource])
26
+ return @@connection_cache[key] if @@connection_cache.has_key? key and @@connection_cache[key].error? == false
27
+
28
+ # Otherwise allocate a new object to do the work
29
+ instance = self.allocate
30
+ instance.send( :initialize, config)
31
+ @@connection_cache[key] = instance
32
+ end
33
+
34
+ ##
35
+ # save out needed information from config, and start up the connection
36
+ TYPE = 0
37
+ HOST = 1
38
+ IPC = 1
39
+ PORT = 2
40
+
41
+ def initialize( config)
42
+ @idenity = config[:idenity].to_s + "[" + Process.pid.to_s + "]"
43
+ @resource = config[:resource].dup
44
+ @include_hostname = config[:include_hostname]
45
+ resource = self.class.parse_resource( config[:resource])
46
+
47
+ @connection = nil
48
+ if resource[TYPE] == :tcp
49
+ # resource[PORT] should return nil considering we only define a pair (resource_type|path)
50
+ @connection = EM.connect( resource[HOST], resource[PORT], Syslog::ConnectionTCP)
51
+ raise "unable to create connection" if @connection.nil?
52
+ @connection.setup( resource[HOST], resource[PORT])
53
+ elsif resource.length == 3
54
+ @connection = EM.open_datagram_socket( '0.0.0.0', 0, Syslog::ConnectionUDP)
55
+ raise "unable to create connection" if @connection.nil?
56
+ @connection.setup( resource[HOST], resource[PORT])
57
+ else
58
+ # need better checking here
59
+ raise "unix domain socket #{resource[IPC]} does not exist!" unless ::File.exists?( resource[IPC])
60
+ c = Syslog::ConnectionUDP::UNIX.create_unix
61
+ @connection = EM.watch( c, Syslog::ConnectionUDP::UNIX)
62
+ raise "unable to create connection" if @connection.nil?
63
+ @connection.setup( c, resource[IPC])
64
+ end
65
+ end
66
+
67
+ ##
68
+ # When called directly we need to make sure we were given valid facilities and severity
69
+
70
+ def log( msg, facility, severity)
71
+ raise "Invalid log severity!" unless Syslog::SEVERITIES.has_key? severity
72
+ raise "Invalid log facility!" unless Syslog::FACILITIES.has_key? facility
73
+ send_log( msg, facility, severity)
74
+ end
75
+
76
+ ##
77
+ #Meta program our facility/severity keys and methods
78
+
79
+ Syslog::FACILITIES.each {|facility,facility_int|
80
+ Syslog::SEVERITIES.each {|severity,severity_int|
81
+ define_method( "#{facility}_#{severity}".to_sym) do |msg|
82
+ send_log( msg, facility, severity)
83
+ end
84
+ class_variable_set("@@syskey_#{facility}_#{severity}".to_sym, (facility_int * 8 + severity_int))
85
+ }
86
+ }
87
+ Syslog::SEVERITIES.each {|severity,severity_int|
88
+ define_method( severity) do |msg,facility|
89
+ send_log( msg, ((facility.nil?) ? :daemons : facility), severity)
90
+ end
91
+ }
92
+
93
+ ##
94
+ # you must fix up the timestamp so that a space is injected in place of a leading 0
95
+ # - returns "Dec 6 12:12:12"
96
+
97
+ def self.timestamp( time=Time.now)
98
+ day = time.strftime("%d")
99
+ day = day.sub(/^0/, ' ') if day =~ /^0\d/
100
+ time.strftime("%b #{day} %H:%M:%S")
101
+ end
102
+
103
+ private
104
+ ##
105
+ # Format and send message to syslog
106
+
107
+ def send_log( msg, facility, severity)
108
+ m = String.new
109
+ m += "<" + self.class.send( :class_variable_get, "@@syskey_#{facility}_#{severity}".to_sym).to_s + ">"
110
+ m += self.class.timestamp + " "
111
+ m += @@hostname + " " if include_hostname
112
+ m += "#{@idenity}: " + msg.to_s
113
+ @connection.send_msg( m)
114
+ end
115
+
116
+ ##
117
+ # Likely not the fastest and best way to make a cache index
118
+ # - returns "#{idenitiy}#{ip|hostname|path.without_dots}"
119
+
120
+ def self.mk_cache_index_key( idenity, resource)
121
+ idenity.to_s + resource.split(':').each {|i| i.gsub(/\./,'') }.join
122
+ end
123
+
124
+ ##
125
+ # Likely not the fastest and best way to parse the syslog resource idenity.
126
+ # unix will always return a set length of 2 and host/port at length 3
127
+ # - returns [ resource_type (:tcp|:udp), ipc_path|ip_address|hostname [, port]]
128
+
129
+ def self.parse_resource( resource)
130
+ split_point = resource.index(':')
131
+ resource_type = resource[0..(split_point-1)].to_sym
132
+ resource = resource[(split_point+1)..-1]
133
+ if resource_type != :tcp and resource_type != :udp
134
+ raise "Invalid resource syntax, protocol must be :tcp|:udp"
135
+ elsif resource[0..1] == "//"
136
+ resource_parts = resource.split('/')
137
+ target_parts = resource_parts[2].split(':')
138
+ raise "Invalid resource syntax: #{resource}" if target_parts.length > 2 or resource_parts.length > 3
139
+ target_parts << 514 if target_parts.length == 1
140
+ target_parts.unshift resource_type
141
+ elsif resource[0,1] == "/"
142
+ target_parts = [ resource_type, resource]
143
+ else
144
+ raise "Invalid resource syntax: can't detect connection type #{resource}"
145
+ end
146
+ target_parts
147
+ end
148
+ end
149
+ end
150
+
@@ -0,0 +1,49 @@
1
+
2
+ module EventMachine
3
+ module Syslog
4
+ ##
5
+ # THIEVERY: http://github.com/kpumuk/ruby_syslog
6
+
7
+ SEVERITIES = {
8
+ :emergency => 0, # system is unusable
9
+ :alert => 1, # action must be taken immediately
10
+ :critical => 2, # critical conditions
11
+ :error => 3, # error conditions
12
+ :warning => 4, # warning conditions
13
+ :notice => 5, # normal but significant condition
14
+ :informational => 6, # informational messages
15
+ :info => 6, # informational messages (short name for the previous)
16
+ :debug => 7 # debug-level messages
17
+ }
18
+
19
+ ##
20
+ # THIEVERY: http://github.com/kpumuk/ruby_syslog
21
+
22
+ FACILITIES = {
23
+ :kernel => 0, # kernel messages
24
+ :user_level => 1, # user-level messages
25
+ :mail => 2, # mail system
26
+ :daemons => 3, # system daemons
27
+ :security => 4, # security/authorization messages
28
+ :internal => 5, # messages generated internally by syslogd
29
+ :printer => 6, # line printer subsystem
30
+ :network => 7, # network news subsystem
31
+ :uucp => 8, # UUCP subsystem
32
+ :clock => 9, # clock daemon
33
+ :security1 => 10, # security/authorization messages
34
+ :ftp => 11, # FTP daemon
35
+ :ntp => 12, # NTP subsystem
36
+ :log_audit => 13, # log audit
37
+ :log_alert => 14, # log alert
38
+ :clock1 => 15, # clock daemon
39
+ :local0 => 16, # local use 0
40
+ :local1 => 17, # local use 1
41
+ :local2 => 18, # local use 2
42
+ :local3 => 19, # local use 3
43
+ :local4 => 20, # local use 4
44
+ :local5 => 21, # local use 5
45
+ :local6 => 22, # local use 6
46
+ :local7 => 23 # local use 7
47
+ }
48
+ end
49
+ end
@@ -0,0 +1,5 @@
1
+ module EventMachine
2
+ module Syslog
3
+ VERSION = "0.0.3"
4
+ end
5
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Digital Akasha
@@ -40,6 +40,12 @@ extensions: []
40
40
  extra_rdoc_files: []
41
41
 
42
42
  files:
43
+ - lib/em-syslog/connection_tcp.rb
44
+ - lib/em-syslog/connection_udp.rb
45
+ - lib/em-syslog/connection_unix.rb
46
+ - lib/em-syslog/logger.rb
47
+ - lib/em-syslog/syslog.rb
48
+ - lib/em-syslog/version.rb
43
49
  - lib/em-syslog.rb
44
50
  has_rdoc: true
45
51
  homepage: https://github.com/tormenta/em-syslog