log4r-xmpp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,107 @@
1
+ = Log4r-XMPP
2
+
3
+ == Description
4
+
5
+ Log4r-XMPP adds a XMPP/Jabber outputter to Log4r.
6
+
7
+ == Installation
8
+
9
+ $ gem install log4r-xmpp
10
+
11
+ == Requirements
12
+
13
+ The following gems are required to use Log4r-XMPP:
14
+
15
+ * log4r
16
+ * xmpp4r (http://home.gna.org/xmpp4r)
17
+
18
+ == Caveats
19
+
20
+ * Do NOT include Log4r into your namespace! XMPP4r uses the generic Logger
21
+ library and would become present in your namespace.
22
+
23
+ == Using Log4r-XMPP
24
+
25
+ Requiring 'log4r-xmpp' will add an XMPPOutputter to Log4r. It is as simple as
26
+ using any other Log4r::Outputter and can use most formatters in addition to the
27
+ default.
28
+
29
+ ===Options:
30
+
31
+ :buffsize => The number of logging events to buffer before sending (default 1)
32
+ :username => Sending user's XMPP/Jabber account username
33
+ :password => Sending user's XMPP/Jabber account password
34
+ :resource => Optional sending user's XMPP/Jabber resource (default 'Log4r')
35
+ :recipients => An array of accounts to send Log4r log statements to
36
+
37
+ ===Example:
38
+
39
+ require 'log4r-xmpp'
40
+
41
+ options = { :buffsize => 10,
42
+ :username => 'log4r@example.com',
43
+ :password => 'secret',
44
+ :resource => 'Log4r',
45
+ :recipients => ['recipient1@example.com', 'recipient2@example.com']
46
+ }
47
+
48
+ outputter = Log4r::XMPPOutputter.new('xmpp', options)
49
+
50
+ mylog = Log4r::Logger.new 'mylog'
51
+ mylog.outputters = outputter
52
+
53
+ mylog.debug "This is a test message sent at level DEBUG"
54
+
55
+ == Using Log4r-XMPP with Log4r::YamlConfigurator
56
+
57
+ Requiring 'log4r-xmpp/yamlconfigurator' will patch Log4r::YamlConfigurator to
58
+ accept an array list of recipients. Substitutions are still taken into
59
+ consideration.
60
+
61
+ ===Example YAML:
62
+
63
+ ---
64
+ # *** YAML2LOG4R ***
65
+ log4r_config:
66
+ # define all loggers ...
67
+ loggers:
68
+ - name : mylog
69
+ level : DEBUG
70
+ trace : 'false'
71
+ outputters:
72
+ - xmpp
73
+
74
+ # define all outputters (incl. formatters)
75
+ outputters:
76
+ - type : XMPPOutputter
77
+ name : 'xmpp'
78
+ buffsize : '10'
79
+ username : 'log4r@localhost'
80
+ password : 'secret'
81
+ resource : "#{RESOURCE}"
82
+ recipients : ["user1@#{DOMAIN}", "user2@#{DOMAIN}"]
83
+ formatter :
84
+ date_pattern: '%y%m%d %H:%M:%S'
85
+ pattern : '%d %l: %m'
86
+ type : PatternFormatter
87
+
88
+ ===Example Loading:
89
+
90
+ require 'log4r-xmpp'
91
+ require 'log4r-xmpp/yamlconfigurator'
92
+
93
+ path = File.dirname(__FILE__)
94
+
95
+ Log4r::YamlConfigurator['RESOURCE'] = 'Log4r-XMPP'
96
+ Log4r::YamlConfigurator['DOMAIN'] = 'localhost'
97
+
98
+ Log4r::YamlConfigurator.load_yaml_file("#{path}/log4r-xmpp.yaml")
99
+
100
+ mylog = Log4r::Logger['mylog']
101
+
102
+ mylog.debug "This is a test message sent at level DEBUG"
103
+
104
+ == Troubleshooting
105
+
106
+ XMPP4r's logger facility logs to an internal logger named 'xmpp4r'. Attach an
107
+ outputter to view additional warning information.
@@ -0,0 +1 @@
1
+ Dir['tasks/*.rake'].sort.each { |taskfile| load taskfile }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,31 @@
1
+ # Copyright 2011 Jonathan P. Voss
2
+ #
3
+ # This file is part of Log4r-XMPP
4
+ #
5
+ # Log4r-XMPP is free software: you can redistribute it and/or modify it under
6
+ # the terms of the GNU General Public License as published by the Free
7
+ # Software Foundation, either version 3 of the License, or (at your option)
8
+ # any later version.
9
+ #
10
+ # Log4r-XMPP is distributed in the hope that it will be useful, but WITHOUT
11
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
+ # for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Log4r-XMPP. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'log4r'
20
+ require 'log4r-xmpp/xmppoutputter'
21
+
22
+ module Log4r
23
+
24
+ class XMPPOutputter
25
+
26
+ VERSION = '0.1.0'
27
+
28
+ end # class XMPPOutputter
29
+
30
+ end # module Log4r
31
+
@@ -0,0 +1,192 @@
1
+ # Copyright 2011 Jonathan P. Voss
2
+ #
3
+ # This file is part of Log4r-XMPP
4
+ #
5
+ # Log4r-XMPP is free software: you can redistribute it and/or modify it under
6
+ # the terms of the GNU General Public License as published by the Free
7
+ # Software Foundation, either version 3 of the License, or (at your option)
8
+ # any later version.
9
+ #
10
+ # Log4r-XMPP is distributed in the hope that it will be useful, but WITHOUT
11
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
+ # for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Log4r-XMPP. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'log4r'
20
+ require 'xmpp4r/client'
21
+
22
+ module Log4r
23
+
24
+ class XMPPOutputter < Outputter
25
+
26
+ attr_reader :username, :password, :resource, :recipients
27
+
28
+ # XMPPOutputter is initialized the same as other Log4r Outputters with the
29
+ # addition of the following hash options:
30
+ #
31
+ # :buffsize => The number of logging events to buffer before sending (default 1)
32
+ # :username => Sending user's XMPP/Jabber account username
33
+ # :password => Sending user's XMPP/Jabber account password
34
+ # :resource => Optional sending user's XMPP/Jabber resource (default 'Log4r')
35
+ # :recipients => Array of usernames to send Log4r log statements to
36
+ #
37
+ # Example:
38
+ #
39
+ # options => { :buffsize => 10,
40
+ # :username => 'log4r@example.com',
41
+ # :password => 'secret',
42
+ # :resource => 'Log4r',
43
+ # :recipients => ['recipient1@example.com', 'recipient2@example.com']
44
+ # }
45
+ #
46
+ # outputter = Log4r::XMPPOutputter.new('xmpp', options)
47
+ #
48
+ # mylog = Log4r::Logger.new 'mylog'
49
+ # mylog.outputters = outputter
50
+ #
51
+ # mylog.debug "This is a test message sent at level DEBUG"
52
+ #
53
+ def initialize(_name, hash={})
54
+
55
+ super(_name, hash)
56
+
57
+ @buff = []
58
+
59
+ begin
60
+
61
+ connect
62
+ Logger.log_internal { "XMPPOutputter '#{@name}' connected as #{@username}"}
63
+
64
+ rescue => e
65
+
66
+ xmpp_error = "#{e.class}: #{e.message}"
67
+
68
+ Logger.log_internal(-2) do
69
+
70
+ "XMPPOutputter '#{@name}' failed to connect to XMPP server: #{xmpp_error}"
71
+
72
+ end # Logger.log_internal
73
+
74
+ end # begin
75
+
76
+ end # def initialize
77
+
78
+ # Connects to the Jabber/XMPP server as a client. This is done automatically
79
+ # during initialization.
80
+ #
81
+ def connect
82
+
83
+ Jabber::logger = Log4r::Logger['xmpp4r'].nil? ? Log4r::Logger.new('xmpp4r')\
84
+ : Log4r::Logger['xmpp4r']
85
+
86
+ # Enable XMPP4r library to log DEBUG events to the internal logger
87
+ #
88
+ Jabber::warnings = true
89
+
90
+ jid = Jabber::JID::new("#{@username}/#{@resource}")
91
+
92
+ @client = Jabber::Client::new(jid)
93
+ @client.connect
94
+ @client.auth(@password)
95
+
96
+ end # def connect
97
+
98
+ # Call to force an outputter to write any buffered log events.
99
+ #
100
+ def flush
101
+
102
+ synch do
103
+
104
+ messages = []
105
+
106
+ @buff.each{ |event| messages.push( format(event) ) }
107
+
108
+ write(messages)
109
+
110
+ end # synch
111
+
112
+ @buff.clear
113
+
114
+ Logger.log_internal { "Flushed XMPPOutputter '#{@name}'" }
115
+
116
+ end # def flush
117
+
118
+ protected
119
+
120
+ # Validates the common hash arguments as required by Log4r then sets up the XMPP options
121
+ # for the outputter.
122
+ #
123
+ def validate_hash(hash)
124
+
125
+ super(hash)
126
+
127
+ # Convert hash keys to symbols if provided as strings (as if configured by YAML)
128
+ hash = hash.inject({}){|temp,(k,v)| temp[k.to_sym] = v; temp}
129
+
130
+ @buffsize = hash[:buffsize].to_i ||= 1
131
+
132
+ @username = hash[:username] or raise ArgumentError, "Username required"
133
+ @password = hash[:password] or raise ArgumentError, "Password required"
134
+ @resource = hash[:resource] ||= 'Log4r'
135
+
136
+ @recipients = hash[:recipients] or raise ArgumentError, "Recipients required"
137
+
138
+ end # def validate_hash
139
+
140
+ private
141
+
142
+ # This method handles all log events passed to this Outputter.
143
+ #
144
+ def canonical_log(event)
145
+
146
+ synch do
147
+
148
+ @buff.push event if @buff.size <= @buffsize
149
+
150
+ flush if @buff.size >= @buffsize
151
+
152
+ end # synch
153
+
154
+ end # def canonical_log
155
+
156
+ # Method to actually write the formatted data to XMPP.
157
+ #
158
+ def write(data)
159
+
160
+ body = ''
161
+
162
+ data.kind_of?(Array) ? data.each{|x| body << x} : body = data
163
+
164
+ [@recipients].flatten.each do |recipient|
165
+
166
+ to = recipient
167
+
168
+ message = Jabber::Message.new(to, body).set_type(:normal).set_id('1')
169
+
170
+ begin
171
+
172
+ @client.send message
173
+
174
+ rescue => e
175
+
176
+ xmpp_error = "#{e.class}: #{e.message}"
177
+
178
+ Logger.log_internal(-2) do
179
+
180
+ "XMPPOutputter '#{@name}' failed to send message: #{xmpp_error}"
181
+
182
+ end # Logger.log_internal
183
+
184
+ end # begin
185
+
186
+ end # @recipients.each
187
+
188
+ end # def write
189
+
190
+ end # class XMPPOutputter
191
+
192
+ end # module Log4r
@@ -0,0 +1,43 @@
1
+ # Copyright 2011 Jonathan P. Voss
2
+ #
3
+ # This file is part of Log4r-XMPP
4
+ #
5
+ # Log4r-XMPP is free software: you can redistribute it and/or modify it under
6
+ # the terms of the GNU General Public License as published by the Free
7
+ # Software Foundation, either version 3 of the License, or (at your option)
8
+ # any later version.
9
+ #
10
+ # Log4r-XMPP is distributed in the hope that it will be useful, but WITHOUT
11
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
+ # for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Log4r-XMPP. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require 'log4r/yamlconfigurator'
20
+
21
+ module Log4r
22
+
23
+ class YamlConfigurator
24
+
25
+ class << self
26
+
27
+ alias_method :paramsub_old, :paramsub
28
+
29
+ end # class << self
30
+
31
+ # Monkey patches paramsub to accept arrays as hash values
32
+ #
33
+ def self.paramsub(str)
34
+
35
+ [str].flatten.each { |val| self.paramsub_old(val) }
36
+
37
+ str.inspect
38
+
39
+ end # def self.paramsub
40
+
41
+ end # class YamlConfigurator
42
+
43
+ end # module Log4r
@@ -0,0 +1,24 @@
1
+ ---
2
+ # *** YAML2LOG4R ***
3
+ log4r_config:
4
+ # define all loggers ...
5
+ loggers:
6
+ - name : mylogger
7
+ level : INFO
8
+ trace : 'false'
9
+ outputters:
10
+ - xmpp
11
+
12
+ # define all outputters (incl. formatters)
13
+ outputters:
14
+ - type : XMPPOutputter
15
+ name : 'xmpp'
16
+ buffsize : '10'
17
+ username : 'log4r@localhost'
18
+ password : 'secret'
19
+ resource : "#{RESOURCE}"
20
+ recipients : ["user1@#{DOMAIN}", "user2@#{DOMAIN}"]
21
+ formatter :
22
+ date_pattern: '%y%m%d %H:%M:%S'
23
+ pattern : '%d %l: %m'
24
+ type : PatternFormatter
@@ -0,0 +1,243 @@
1
+ # Copyright 2011 Jonathan P. Voss
2
+ #
3
+ # This file is part of Log4r-XMPP
4
+ #
5
+ # Log4r-XMPP is free software: you can redistribute it and/or modify it under
6
+ # the terms of the GNU General Public License as published by the Free
7
+ # Software Foundation, either version 3 of the License, or (at your option)
8
+ # any later version.
9
+ #
10
+ # Log4r-XMPP is distributed in the hope that it will be useful, but WITHOUT
11
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
+ # for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Log4r-XMPP. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+
19
+ require "rspec"
20
+ require "log4r-xmpp"
21
+ require "log4r-xmpp/yamlconfigurator"
22
+
23
+ describe "XMPP Outputter" do
24
+
25
+ before(:each) do
26
+
27
+ @options = { :buffsize => 10,
28
+ :username => 'log4r@localhost',
29
+ :password => 'secret',
30
+ :resource => 'Log4r',
31
+ :recipients => ['testuser@localhost']
32
+ }
33
+
34
+ @outputter = Log4r::XMPPOutputter.new('xmpp', @options)
35
+
36
+ @log = Log4r::Logger.new 'testlog'
37
+ @log.outputters = @outputter
38
+
39
+ end # before(:all)
40
+
41
+ after(:each) do
42
+
43
+ @log = nil
44
+
45
+ end # after(:each)
46
+
47
+ describe "initialization" do
48
+
49
+ it "should require a username" do
50
+
51
+ options = @options.dup
52
+ options.delete(:username)
53
+
54
+ l = lambda { Log4r::XMPPOutputter.new('xmpp', options) }
55
+
56
+ l.should raise_error(ArgumentError)
57
+
58
+ end # it "should require a username"
59
+
60
+ it "should require a password" do
61
+
62
+ options = @options.dup
63
+ options.delete(:password)
64
+
65
+ l = lambda { Log4r::XMPPOutputter.new('xmpp', options) }
66
+
67
+ l.should raise_error(ArgumentError)
68
+
69
+ end # it "should require a password"
70
+
71
+ it "should require recipients" do
72
+
73
+ options = @options.dup
74
+ options.delete(:recipients)
75
+
76
+ l = lambda { Log4r::XMPPOutputter.new('xmpp', options) }
77
+
78
+ l.should raise_error(ArgumentError)
79
+
80
+ end # it "should require recipients"
81
+
82
+ it "should not require a buffer size" do
83
+
84
+ options = @options.dup
85
+ options.delete(:buffsize)
86
+
87
+ l = lambda { Log4r::XMPPOutputter.new('xmpp', options) }
88
+
89
+ l.should_not raise_error(ArgumentError)
90
+
91
+ end # it "should not require a buffer size"
92
+
93
+ it "should not require a resource" do
94
+
95
+ options = @options.dup
96
+ options.delete(:resource)
97
+
98
+ l = lambda{ Log4r::XMPPOutputter.new('xmpp', options) }
99
+
100
+ l.should_not raise_error(ArgumentError)
101
+
102
+ end # it "should not require a resource"
103
+
104
+ end # describe "initialization"
105
+
106
+ describe "Log4r support" do
107
+
108
+ it "should satisfy Log4r::Outputter requirements" do
109
+
110
+ # Public Instance Methods
111
+ flush = :flush
112
+ formatter = :formatter
113
+ level = :level
114
+ only_at = :only_at
115
+
116
+ # Protected Instance Methods
117
+ validate_hash = :validate_hash
118
+
119
+ # Private Instance Methods
120
+ canonical_log = :canonical_log
121
+ format = :format
122
+ synch = :synch
123
+ write = :write
124
+
125
+ # Pre Ruby 1.9, method arrays included strings instead of symbols
126
+ if RUBY_VERSION < '1.9'
127
+
128
+ canonical_log = canonical_log.to_s
129
+ flush = flush.to_s
130
+ format = format.to_s
131
+ formatter = formatter.to_s
132
+ level = level.to_s
133
+ only_at = only_at.to_s
134
+ synch = synch.to_s
135
+ validate_hash = validate_hash.to_s
136
+ write = write.to_s
137
+
138
+ end # if RUBY_VERSION
139
+
140
+ @outputter.public_methods.include?(flush).should == true
141
+ @outputter.public_methods.include?(formatter).should == true
142
+ @outputter.public_methods.include?(level).should == true
143
+ @outputter.public_methods.include?(only_at).should == true
144
+
145
+ @outputter.protected_methods.include?(validate_hash).should == true
146
+
147
+ @outputter.private_methods.include?(canonical_log).should == true
148
+ @outputter.private_methods.include?(format).should == true
149
+ @outputter.private_methods.include?(synch).should == true
150
+ @outputter.private_methods.include?(write).should == true
151
+
152
+ end # it "should satisfy Log4r::Outputter requirements"
153
+
154
+ it "should accept strings as keys in the configuration hash" do
155
+
156
+ options = { 'buffsize' => 10,
157
+ 'username' => 'log4r@localhost',
158
+ 'password' => 'secret',
159
+ 'resource' => 'Log4r',
160
+ 'recipients' => ['testuser@localhost']
161
+ }
162
+
163
+ outputter = Log4r::XMPPOutputter.new('xmpp', options)
164
+
165
+ log = Log4r::Logger.new 'testlog'
166
+ log.outputters = @outputter
167
+
168
+ log.outputters[0].username.should == options['username']
169
+ log.outputters[0].password.should == options['password']
170
+ log.outputters[0].resource.should == options['resource']
171
+ log.outputters[0].recipients.should == options['recipients']
172
+
173
+ end # it "should accept strings as keys in the configuration hash" do
174
+
175
+ it "should satisfy Log4r::YamlConfigurator requirements" do
176
+
177
+ path = File.dirname(__FILE__)
178
+
179
+ Log4r::YamlConfigurator['RESOURCE'] = 'Log4r-XMPP'
180
+ Log4r::YamlConfigurator['DOMAIN'] = 'localhost'
181
+
182
+ Log4r::YamlConfigurator.load_yaml_file("#{path}/log4r-xmpp.yaml")
183
+
184
+ log = Log4r::Logger['mylogger']
185
+
186
+ log.outputters[0].class.should == Log4r::XMPPOutputter
187
+ log.outputters[0].username.should == 'log4r@localhost'
188
+ log.outputters[0].password.should == 'secret'
189
+ log.outputters[0].resource.should == 'Log4r-XMPP'
190
+ log.outputters[0].recipients.should == ['user1@localhost', 'user2@localhost']
191
+
192
+ end # it "should satisfy Log4r::YamlConfigurator requirements"
193
+
194
+ end # describe "Log4r support"
195
+
196
+ describe "logging events" do
197
+
198
+ it "should buffer messages" do
199
+
200
+ message = "This is a message with level DEBUG"
201
+
202
+ response = @log.debug message
203
+ buff = response[0].instance_variable_get(:@buff)
204
+
205
+ buff.empty?.should_not == true
206
+ buff.class.should == Array
207
+ buff[0].data.should == message
208
+
209
+ buff.clear
210
+
211
+ end # it "should send messages"
212
+
213
+ it "should flush messages when the buffer is full" do
214
+
215
+ @outputter.should_receive(:flush)
216
+
217
+ @options[:buffsize].times { @log.debug "Test message" }
218
+
219
+ end # it "should send messages"
220
+
221
+ it "flush should clear the buffer after messages are sent" do
222
+
223
+ @options[:buffsize].times { @log.debug "Test message" }
224
+
225
+ buffer = @outputter.instance_variable_get(:@buff)
226
+
227
+ buffer.empty?.should == true
228
+
229
+ end # it "flush should clear the buffer after being sent"
230
+
231
+ it "should send messages to Jabber server" do
232
+
233
+ jabber = @outputter.instance_variable_get(:@client)
234
+
235
+ jabber.should_receive(:send).exactly(1).times
236
+
237
+ @options[:buffsize].times { @log.debug "Test message" }
238
+
239
+ end # it "should send messages to XMPP server"
240
+
241
+ end # describe "logging events"
242
+
243
+ end # describe "XMPP Outputter"