em-syslog-logger 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/em-syslog.rb +224 -0
  2. metadata +76 -0
data/lib/em-syslog.rb ADDED
@@ -0,0 +1,224 @@
1
+
2
+ require 'socket'
3
+ require 'rubygems'
4
+ require 'eventmachine'
5
+
6
+ module EventMachine
7
+ 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
+ }
47
+
48
+ def self.logger( *a)
49
+ EventMachine::Logger.new( *a)
50
+ 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
+ end
210
+ end
211
+
212
+ if __FILE__ == $0
213
+ EM.run {
214
+ EM.kqueue if EM.kqueue?
215
+ EM.epoll if EM.epoll?
216
+
217
+ logger = EM::Syslog.logger( "em-syslog-test")
218
+ EM.next_tick {
219
+ logger.log( "TEST INFO", :daemons, :info)
220
+ logger.mail_error( "MAIL ERROR")
221
+ }
222
+ }
223
+ end
224
+
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-syslog-logger
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Digital Akasha
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2012-12-12 00:00:00 -06:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: eventmachine
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 12
30
+ - 10
31
+ version: 0.12.10
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description:
35
+ email: tormenta@digitalakasha.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - lib/em-syslog.rb
44
+ has_rdoc: true
45
+ homepage: https://github.com/tormenta/em-syslog
46
+ licenses: []
47
+
48
+ post_install_message:
49
+ rdoc_options: []
50
+
51
+ require_paths:
52
+ - lib
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ requirements: []
69
+
70
+ rubyforge_project:
71
+ rubygems_version: 1.3.6
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: Simple Logger Class For Eventmachine Applications
75
+ test_files: []
76
+