module logging; // Simple logging facility private: import std.format,std.string, std.file, std.stdio; char[] basedir = "."; LogFile[ char[] ] named_logs; class LogFile { char[] id; char[] buffer; int flush_after = 1024; uint total_written = 0; int max_size = int.max; this( char[] _id ) { id = strip(_id); if ( id=="" ) id="default"; remove_old_file(); } char[] filename() { return basedir ~ "/" ~ id ~ ".log" ; } char[] backup() { return basedir ~ "/" ~ id ~ ".bak" ; } void remove_old_file() { if ( std.file.exists( filename )==false ) return; if ( std.file.exists( backup ) ) { if ( std.file.isdir( backup ) ) return; std.file.remove( backup ); } std.file.rename( filename, backup ); } void write( TypeInfo[] types, void* argptr ) { if ( total_written > max_size ) return; char[] line = ""; int index = 0; try { void accept( dchar c ) { line~= c; } doFormat( &accept, types, argptr ); } catch( Exception e ) { writefln("Exception writing log: %s", e.msg ); } buffer ~= (line ~ '\n' ); total_written += line.length; if ( ( total_written >= max_size )|| ( buffer.length >= flush_after ) ) flush(); } private void flush() { if ( buffer.length==0 ) return; std.file.append( filename, cast(void[])buffer ); buffer.length = 0; } } LogFile findLog( char[] id ) { id = tolower( strip( id ) ); LogFile* ptr = (id in named_logs ); if ( ptr !is null ) return ptr[0]; LogFile logfile = new LogFile( id ); named_logs[id] = logfile; return logfile; } static ~this() { FlushLogs(); } public: void FlushLogs() { foreach( char[] id, LogFile log; named_logs ) log.flush(); } void SetLoggingDir( char[] dir ) { if ( !isdir( dir ) ) throw new Exception( format( "Logging Directory '%s' does not exist!", dir ) ); while((dir.length>0) && (dir[ dir.length-1 ]=='/') ) dir.length = dir.length-1; basedir = dir.dup; } void SetLogBufferSize( uint sz ) { foreach( char[] n, LogFile f; named_logs ) f.flush_after = sz; } void SetLogBufferSize( char[] id, uint sz ) { findLog( id ).flush_after = sz; } void SetMaxLogSize( uint sz ) { foreach( char[] n, LogFile f; named_logs ) f.max_size = sz; } void SetMaxLogSize( char[] id, uint sz ) { findLog(id).max_size = sz; } void Log( char[] id, ... ) { findLog(id).write( _arguments, _argptr ); } // typical logging helper functions void LogInfo( ... ) { findLog( "info" ).write( _arguments, _argptr ); } void LogWarning( ... ) { findLog( "warning" ).write( _arguments, _argptr ); } void LogError( ... ) { findLog( "error" ).write( _arguments, _argptr ); } void LogFatal( ... ) { findLog( "fatal" ).write( _arguments, _argptr ); } void DebugLogs() { writefln( "Begin Log Debug Info *****" ); foreach( char[] n, LogFile log ; named_logs ) { writefln( "Log: %s", n ); writefln( "Max size: %s", log.max_size ); writefln( "Chars written: %s", log.total_written ); writefln( "Chars in buffer: %s", log.buffer.length ); writefln( "Flush after %s:", log.flush_after ); writefln(); } writefln( "End Log Debug Info *****" ); }