log4r-xmpp 0.1.0

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,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"