1
# Copyright 2008 Amazon.com, Inc. or its affiliates. All Rights
2
# Reserved. Licensed under the Amazon Software License (the
3
# "License"). You may not use this file except in compliance with the
4
# License. A copy of the License is located at
5
# http://aws.amazon.com/asl or in the "license" file accompanying this
6
# file. This file is distributed on an "AS IS" BASIS, WITHOUT
7
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See
8
# the License for the specific language governing permissions and
9
# limitations under the License.
16
# generate a unique identifier used for filenames
19
(0..19).inject("") {|ident, n| ident+(?A + Kernel.rand(26)).chr}
22
#------------------------------------------------------------------------------#
24
# A thread local buffer manager. Provide's each thread with a single
25
# pre-allocated IO buffer. IMPORTANT: as these buffers are indexed in a
26
# hashtable they will not be freed until the application closes. If a thread
27
# needs to free the memory its buffer is using, it must call
28
# <code>delete_buffer</code> and ensure it has no references to the buffer.
29
class ThreadLocalBuffer
30
POWER = 12 # Log SIZE base 2
31
SIZE = 2**POWER # Size of the buffer.
33
@@buffers.extend( MonitorMixin )
35
#----------------------------------------------------------------------------#
37
# Return the thread's buffer.
38
def ThreadLocalBuffer.get_buffer
39
@@buffers.synchronize do
40
@@buffers[Thread.current] = new_buffer unless @@buffers.has_key?( Thread.current )
41
@@buffers[Thread.current]
45
#----------------------------------------------------------------------------#
47
# Delete the threads buffer.
48
def delete_buffer buffer
49
@@buffers.delete buffer
52
#----------------------------------------------------------------------------#
54
def ThreadLocalBuffer.new_buffer
56
buffer = Format::hex2bin( '00' )
57
POWER.times { buffer << buffer }
61
private_class_method :new_buffer
64
#------------------------------------------------------------------------------#
67
# Base class for XML-RPC structures. Stores key and values pairs. Key names are
68
# mapped to method names by converting '-' to '_' characters.
70
class XMLRPCStruct < Hash
71
# _members_ A list of the structure's key names or nil if any key names
73
def initialize members
74
unless members.kind_of? Array or members.nil?
75
raise ArgumentError.new( "invalid members argument" )
80
# Provide direct access to individual instance elements by methods named after
82
def method_missing( method_symbol, argument=nil )
83
# Here kid, play with this loaded gun...
84
method = method_symbol.to_s
86
# Determine if setter or getter call and remove '=' if setter.
87
setter = /[\S]+=/.match(method)
88
member = (setter ? method.slice(0, method.size - 1) : method)
90
# Map method name to member name.
91
member = member.gsub('_', '-')
93
# If valid attribute set or get accordingly. If the member list is nil then
94
# any members are allowed.
95
if @members.nil? or @members.include?( member )
97
raise ArgumentError, "value for key #{member} may not be nil" if argument.nil?
98
self[member] = argument
103
raise NoMethodError.new( method )
108
#------------------------------------------------------------------------------#
111
# Note to self - use log4r next time ;)
114
#----------------------------------------------------------------------------#
116
# @deprecated use Priority instead
118
private_class_method :new
123
@@levels[value] = self
126
V0 = new 0 # Unhandled exceptions only.
127
V1 = new 1 # As for 0 but with error messages.
128
V2 = new 2 # As for 1 but with informational messages.
129
V3 = new 3 # As for 2 but with XML-RPC logging.
130
V4 = new 4 # As for 3 but with Xen logging.
131
V5 = new 5 # As for 4 but with debugging messages.
136
@value >= operand.value
139
def Verbosity.from_string s
141
if not @@levels[level]
142
raise ArgumentError.new("invalid logging verbosity level #{level}")
151
return Priority::ALERT
155
return Priority::WARNING
157
return Priority::NOTICE
159
return Priority::INFO
161
return Priority::DEBUG
166
#----------------------------------------------------------------------------#
169
private_class_method :new
173
@value = (name == "AES")?(12<<3):eval("Syslog::LOG_#{name}")
176
AUTHPRIV = new "AUTHPRIV"
178
DAEMON = new "DAEMON"
181
LOCAL0 = new "LOCAL0"
182
LOCAL1 = new "LOCAL1"
183
LOCAL2 = new "LOCAL2"
184
LOCAL3 = new "LOCAL3"
185
LOCAL4 = new "LOCAL4"
186
LOCAL5 = new "LOCAL5"
187
LOCAL6 = new "LOCAL6"
188
LOCAL7 = new "LOCAL7"
192
SYSLOG = new "SYSLOG"
201
"Facility[LOG_#{@name}]"
205
#----------------------------------------------------------------------------#
210
private_class_method :new
214
@value = eval("Syslog::LOG_#{name}")
217
EMERG = new "EMERG" # 0
218
ALERT = new "ALERT" # 1
219
CRIT = new "CRIT" # 2
221
WARNING = new "WARNING" # 4
222
NOTICE = new "NOTICE" # 5
223
INFO = new "INFO" # 6
224
DEBUG = new "DEBUG" # 7
230
@value <=> priority.value
234
"Priority[LOG_#{@name}]"
238
#----------------------------------------------------------------------------#
240
@@facility = Facility::AES
241
@@priority = Priority::INFO
243
@@streams_mutex = Mutex.new
246
#----------------------------------------------------------------------------#
249
# Set the verbosity of the logging.
250
# @deprecated use set_priority
251
def Log.set_verbosity(verbosity)
252
set_priority(verbosity.to_priority)
255
#----------------------------------------------------------------------------#
258
# Set the IO instance to log to.
259
# @deprecated use add_stream
264
#----------------------------------------------------------------------------#
267
# Log a debug message.
268
def Log.debug(msg=nil)
270
write(Priority::DEBUG) {yield}
272
write(Priority::DEBUG) {msg}
276
#----------------------------------------------------------------------------#
279
# Log a warning message.
280
def Log.warn(msg=nil)
282
write(Priority::WARNING) {yield}
284
write(Priority::WARNING) {msg}
288
#----------------------------------------------------------------------------#
291
# Log an informational message.
292
def Log.info(msg=nil)
294
write(Priority::INFO) {yield}
296
write(Priority::INFO) {msg}
300
#----------------------------------------------------------------------------#
303
# Log an error message.
306
write(Priority::ERR) {yield}
308
write(Priority::ERR) {msg}
312
#----------------------------------------------------------------------------#
315
# Log a warning message.
316
def Log.warn(msg=nil)
318
write(Priority::WARNING) {yield}
320
write(Priority::WARNING) {msg}
324
#----------------------------------------------------------------------------#
327
# Log an unhandled exception.
328
# @deprecated use write
331
write(Priority::ALERT) {yield}
333
write(Priority::ALERT) {Log.exception_str(e)}
337
#----------------------------------------------------------------------------#
340
# Log an informational message.
341
# @deprecated use write
343
write(Verbosity::V2.to_priority) {msg}
346
#----------------------------------------------------------------------------#
348
# @deprecated use write
350
write(Verbosity::V4.to_priority) {msg}
353
#----------------------------------------------------------------------------#
355
# @deprecated use write
356
def Log.xmlrpcmethod_call(name, *paramstructs)
357
write(Verbosity::V3.to_priority) {Log.xmlrpcmethod_call_str(name, paramstructs)}
360
#----------------------------------------------------------------------------#
362
# @deprecated use write
363
def Log.xmlrpcmethod_return(name, value)
364
write(Verbosity::V3.to_priority) {Log.xmlrpcmethod_return_str(name, value)}
367
#----------------------------------------------------------------------------#
369
# @deprecated use write
370
def Log.xmlrpcfault(xmlrpc_method, fault)
371
write(Verbosity::V3.to_priority) {Log.xmlrpcfault_str(xmlrpc_method, fault)}
374
#----------------------------------------------------------------------------#
377
# Add an additional stream (like a file, or $stdout) to send
380
def Log.add_stream(stream)
381
@@streams_mutex.synchronize do
382
@@streams.push(stream)
383
@@streams.delete_if { |io| io.closed? }
387
#----------------------------------------------------------------------------#
389
def Log.exception_str(e)
390
e.message + "\n" + e.backtrace.to_s
393
#----------------------------------------------------------------------------#
395
def Log.xmlrpcfault_str(xmlrpc_method, fault)
396
"XML-RPC method fault\nmethod: #{xmlrpc_method}\nfault code: #{fault.faultCode}\nfault string: #{fault.faultString}"
399
#----------------------------------------------------------------------------#
401
def Log.xmlrpcmethod_call_str(name, *paramstructs)
402
msg = "name: #{name}\n"
403
paramstructs.each_index { |i| msg += "parameter #{i + 1}: #{paramstructs[i].inspect}\n" }
404
"XML-RPC method call\n#{msg}"
407
#----------------------------------------------------------------------------#
409
def Log.xmlrpcmethod_return_str(name, value)
410
msg = "name: #{name}\nvalue: #{value.inspect}"
411
"XML-RPC method return\n#{msg}"
414
#----------------------------------------------------------------------------#
417
# Set the minimum priority of the logging. Messages logged with a
418
# lower (less urgent) priority will be ignored.
420
def Log.set_priority(priority)
421
@@priority = priority
424
#----------------------------------------------------------------------------#
427
# Set the facility to log messages against when no explicit facility is
430
def Log.set_facility(facility)
431
@@facility = facility
434
#----------------------------------------------------------------------------#
437
# Set the identity to log messages against when no explicit identity is
438
# provided. If no identity is provided (either using this method or explicitly
439
# when logging) the system will use the application name as the identity.
441
def Log.set_identity(identity)
442
@@identity = identity
445
#----------------------------------------------------------------------------#
447
SYSLOG_OPTS = (Syslog::LOG_PID | Syslog::LOG_CONS)
449
#----------------------------------------------------------------------------#
455
private_class_method :time
457
#----------------------------------------------------------------------------#
459
def Log.write(priority=Priority::DEBUG, facility=nil, identity=nil)
460
# If the priority of this message is below the defined priority
461
# for logging then we don't want to do this at all. NOTE: Priorities
462
# for syslog are defined in ascending order (so lower priorities
464
return unless priority <= @@priority
465
return unless block_given?
468
facility = (facility == nil)?(@@facility):(facility)
469
fac_int = facility.value
470
ident = (identity == nil)?(@@identity):(identity)
472
Syslog.open(ident, SYSLOG_OPTS, fac_int) do |log|
473
log.log(priority.value, '%s', msg)
476
# Now pass the message onto each registered stream
477
# Access to our list of streams is synchronized so that it can be changed
479
@@streams_mutex.synchronize do
480
@@streams.each do |stream|
482
stream.puts "#{time}: #{ident}: #{priority.value}: #{msg}"
484
rescue Exception => e
485
$stderr.puts 'error writing to stream [#{stream}], logging to stdout'
489
rescue Exception => e
490
$stderr.puts "error loggin to syslog, logging to stdout: #{e}"
493
$stdout.puts "Msg: #{msg}"
494
rescue Exception => e
495
$stderr.puts "Block raised error: #{e}"
502
#------------------------------------------------------------------------------#
505
# Utilities used for logging (in order for compatability between AESLogger and the previous Log class)
510
# Prevent instantiation
511
private_class_method :new
513
def LogUtils.exception_str(e)
514
e.message + "\n" + e.backtrace.to_s
517
def LogUtils.xmlrpcfault_str(xmlrpc_method, fault)
518
"XML-RPC method fault : method: #{xmlrpc_method} : fault code: #{fault.faultCode} : fault string: #{fault.faultString}"
521
def LogUtils.xmlrpcmethod_call_str(name, *paramstructs)
522
msg = "name: #{name} : "
523
paramstructs.each_index { |i| msg += "parameter #{i + 1}: #{paramstructs[i].inspect} : " }
524
"XML-RPC method call\n#{msg}"
527
def LogUtils.xmlrpcmethod_return_str(name, value)
528
msg = "name: #{name} : value: #{value.inspect}"
529
"XML-RPC method return : #{msg}"