214 lines
5.7 KiB
Ruby
Executable File
214 lines
5.7 KiB
Ruby
Executable File
#
|
|
# logxml.rb
|
|
# XML File Log Target
|
|
#
|
|
# Author:: David Muir <david.muir@rockstarnorth.com>
|
|
# Date:: 10 March 2008
|
|
#
|
|
|
|
require 'pipeline/log/erblogtranslator'
|
|
require 'pipeline/log/log'
|
|
require 'pipeline/log/rollingdatefileoutputter'
|
|
require 'pipeline/util/debug'
|
|
|
|
require 'erb'
|
|
require 'log4r'
|
|
require 'rexml/document'
|
|
|
|
module Pipeline
|
|
|
|
#
|
|
# == Description
|
|
# XML file outputter formatter class.
|
|
#
|
|
class XMLFormatter < Log4r::Formatter
|
|
|
|
# This method is invoked automatically by the Log4r system.
|
|
def format( event )
|
|
|
|
# If we have trace functionality we are a little more verbose in
|
|
# our XML output.
|
|
output = ""
|
|
message = event.data.gsub( '"', '\'' ).gsub( /\n/, '' )
|
|
if ( !event.tracer.nil? )
|
|
ti = parse_trace_info( event )
|
|
|
|
output += "<event timestamp=\"#{DateTime.now.strftime('%Y-%m-%d %H:%M:%S')}\" type=\"#{::Log4r::LNAMES[event.level]}\" message=\"#{message}\">"
|
|
output += "<trace file=\"#{ti[:filename]}\" line=\"#{ti[:lineno]}\" method=\"#{ti[:function]}\" />"
|
|
output += "</event>"
|
|
else
|
|
|
|
output += "<event timestamp=\"#{DateTime.now.strftime('%Y-%m-%d %H:%M:%S')}\" type=\"#{::Log4r::LNAMES[event.level]}\" message=\"#{message}\" />"
|
|
end
|
|
|
|
output
|
|
end
|
|
|
|
#---------------------------------------------------------------------
|
|
# Private Methods
|
|
#---------------------------------------------------------------------
|
|
private
|
|
|
|
def parse_trace_info( event )
|
|
|
|
trace_info = {}
|
|
matches = /^(.*)\:([0-9]+):in .([A-Za-z0-9_]+)./.match( event.tracer[0] )
|
|
|
|
if ( ( nil != matches ) and ( matches.size >= 4 ) ) then
|
|
trace_info[:filename] = matches[1]
|
|
trace_info[:lineno] = matches[2]
|
|
trace_info[:function] = matches[3]
|
|
else
|
|
trace_info[:filename] = ''
|
|
trace_info[:lineno] = '-1'
|
|
trace_info[:function] = ''
|
|
end
|
|
|
|
# Return our hash with trace information
|
|
trace_info
|
|
end
|
|
end
|
|
|
|
#
|
|
# == Description
|
|
# XML File Logger outputter class.
|
|
#
|
|
class XMLFileOutputter < Log4r::FileOutputter
|
|
|
|
def initialize( _name, hash={} )
|
|
super( _name, hash )
|
|
validate_hash( hash )
|
|
|
|
write_header()
|
|
|
|
# Ensure we close the log at program exit. This ensures we write
|
|
# the XML footer tags to construct a valid XML document.
|
|
at_exit { self.close() }
|
|
end
|
|
|
|
def close
|
|
begin
|
|
# Finish XML tags, and close file.
|
|
write_footer()
|
|
super()
|
|
|
|
pretty_print()
|
|
translate_to_html()
|
|
rescue Exception => ex
|
|
|
|
print_exception( ex )
|
|
end
|
|
end
|
|
|
|
#---------------------------------------------------------------------
|
|
# Protected
|
|
#---------------------------------------------------------------------
|
|
|
|
protected
|
|
|
|
def write_header( )
|
|
@out.write( "<?xml version=\"1.0\" ?>" )
|
|
@out.write( "<log name=\"#{@name}\">" )
|
|
end
|
|
|
|
def write_footer( )
|
|
@out.write( "</log>" )
|
|
end
|
|
|
|
def pretty_print( )
|
|
|
|
replace_filename = OS::Path.replace_ext( @filename, 'orig' )
|
|
FileUtils.cp( @filename, replace_filename )
|
|
File.open( replace_filename, "r" ) do |xmlinfile|
|
|
File.open( @filename, 'w' ) do |xmloutfile|
|
|
logxml = REXML::Document.new( xmlinfile )
|
|
logxml.xml_decl.encoding = "UTF-8"
|
|
fmt = REXML::Formatters::Pretty.new( )
|
|
fmt.write( logxml, xmloutfile )
|
|
end
|
|
end
|
|
FileUtils.rm( replace_filename )
|
|
end
|
|
|
|
def translate_to_html( )
|
|
|
|
# Setup a XML log translator to translate our log into HTML, if the
|
|
# user has the generate html log option set.
|
|
if ( Pipeline::Config.instance.log_generate_html ) then
|
|
puts "Generating HTML log from #{@filename}..."
|
|
erb_path = OS::Path.combine( Config.instance.toolsbin, 'pipeline', 'log', 'erb', 'htmllog.erb' )
|
|
translator = ErbLogTranslator.new( @filename, erb_path )
|
|
translator.translate()
|
|
translator.save( OS::Path.replace_ext( @filename, 'html' ) )
|
|
end
|
|
end
|
|
|
|
def validate_hash( hash )
|
|
super( hash )
|
|
@formatter = XMLFormatter.new
|
|
end
|
|
end
|
|
|
|
#
|
|
# == Description
|
|
#
|
|
#
|
|
#
|
|
class XMLRollingDateFileOutputter < XMLFileOutputter
|
|
def initialize( _name, hash={} )
|
|
super( _name, hash )
|
|
@created_at = Time.now
|
|
|
|
@filename_base = OS::Path.get_basename( @filename )
|
|
@filename_ext = OS::Path.get_extension( @filename )
|
|
end
|
|
|
|
#---------------------------------------------------------------------
|
|
# Private Methods
|
|
#---------------------------------------------------------------------
|
|
|
|
private
|
|
|
|
def write( data )
|
|
roll if requires_roll
|
|
super
|
|
end
|
|
|
|
def get_archive_filename()
|
|
newbase = "#{@filename_base}-#{@created_at.strftime('%Y-%m-%d')}.#{@filename_ext}"
|
|
OS::Path.combine( OS::Path.get_directory( @filename ), newbase )
|
|
end
|
|
|
|
def requires_roll()
|
|
@created_at.day != Time.now.day
|
|
end
|
|
|
|
def roll()
|
|
begin
|
|
write_footer()
|
|
@out.close()
|
|
pretty_print()
|
|
translate_to_html()
|
|
|
|
archive_filename = get_archive_filename()
|
|
html_filename = OS::Path.replace_ext( @filename, 'html' )
|
|
archive_html_filename = OS::Path.replace_ext( archive_filename, 'html' )
|
|
OS::FileUtilsEx.move_file( @filename, archive_filename )
|
|
OS::FileUtilsEx.move_file( html_filename, archive_html_filename )
|
|
FileUtils.rm( @filename )
|
|
FileUtils.rm( html_filename )
|
|
rescue Exception => ex
|
|
Log4r::Logger.log_internal do
|
|
"XMLRollingDateFileOutputter exception: #{ex.message}"
|
|
end
|
|
end
|
|
@created_at = Time.now
|
|
@out = File.new( @filename, "w" )
|
|
write_header()
|
|
end
|
|
end
|
|
|
|
end # Pipeline module
|
|
|
|
# End of logxml.rb
|