Files
2025-09-29 00:52:08 +02:00

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