2014-01-23 17:17:54 -06:00
// Module dependences
var util = require ( 'util' )
, mkdirp = require ( 'mkdirp' )
, path = require ( 'path' )
, moment = require ( 'moment' )
, fs = require ( 'fs' ) ;
2014-05-18 22:32:33 -05:00
var APP _NAME = "APP_NAME" ;
var LOG _PATH = _ _dirname + "/log" ;
2014-01-23 17:17:54 -06:00
// Logger information which will be read by the 'overload' function when
// assigning the roles of each I/O scribes.
var loggers = {
types : {
// Method to override
log : {
// File storage?
file : true ,
// Prinout to console?
console : true ,
} ,
2014-05-18 22:32:33 -05:00
info : { file : true , console : true } ,
error : { file : true , console : true } ,
warn : { file : true , console : true , } ,
realtime : { file : true , console : true } ,
high : { file : true , console : true } ,
normal : { file : true , console : true } ,
low : { file : true , console : true }
2014-01-23 17:17:54 -06:00
} ,
colors : {
// Console tag colors
info : 'green' , // Done events
log : 'yellow' , // Large data
warn : 'cyan' , // To do events
error : 'red' , // To do events
realtime : 'blue' ,
high : 'magenta' ,
normal : 'grey' ,
low : 'grey'
} ,
settings : {
maxTagLength : 30 ,
preIndent : 5 ,
2014-05-18 22:32:33 -05:00
divider : 'W5JZ6WS4GY' ,
2014-01-23 17:17:54 -06:00
defaultTag : '[' + APP _NAME + ']' ,
userName : 'unkown'
}
} ;
2014-05-18 22:32:33 -05:00
var logpath = LOG _PATH ;
2014-01-23 17:17:54 -06:00
2014-05-18 22:32:33 -05:00
var createdir = function ( ) {
2014-01-23 17:17:54 -06:00
var userName = process . env [ ( process . platform == 'win32' ) ? 'USERPROFILE' : 'HOME' ] . toLowerCase ( ) ;
loggers . settings . userName = userName . slice ( userName . lastIndexOf ( '\\' ) + 1 ) ;
// Create daily logger directory
2014-05-18 22:32:33 -05:00
var fpath = path . join ( LOG _PATH , "log" . toLowerCase ( ) ) ;
2014-01-23 17:17:54 -06:00
// Create daily logger directory
2014-01-31 16:30:29 -06:00
var dailyPath = path . join ( fpath , moment ( ) . format ( 'MMM_D_YY' ) . toLowerCase ( ) ) ;
2014-01-23 17:17:54 -06:00
// Create user directories
2014-01-31 16:30:29 -06:00
var userPath = path . join ( dailyPath , loggers . settings . userName ) ;
try
{
// Create directories syncrhonized.
mkdirp . sync ( fpath , 0777 & ( ~ process . umask ( ) ) ) ;
mkdirp . sync ( dailyPath , 0777 & ( ~ process . umask ( ) ) ) ;
mkdirp . sync ( userPath , 0777 & ( ~ process . umask ( ) ) ) ;
}
catch ( error )
{
2014-01-31 16:32:39 -06:00
console . error ( "[Scribe] Major error detected. Please post an issue on Github." ) ;
2014-01-31 16:31:46 -06:00
console . error ( error ) ;
2014-01-31 16:30:29 -06:00
throw error ;
}
2014-01-23 17:17:54 -06:00
2014-05-18 22:32:33 -05:00
return userPath ;
}
var overload = function ( ) {
// Additional transports
console . realtime = console . info ;
console . high = console . info ;
console . normal = console . info ;
console . low = console . info ;
2014-01-31 16:30:29 -06:00
// Assign this variable as write directory
2014-05-18 22:32:33 -05:00
var dayiso = moment ( ) . isoWeekday ( ) ; // FIXME Remove this
var fpath = logpath = createdir ( ) ;
2014-01-23 17:17:54 -06:00
var _sps = function ( sp ) {
var s = '' ;
for ( var z = 0 ; z < sp ; z ++ )
s += ' ' ;
return s ;
}
// Authorize and overload the loggers
for ( var m in loggers . types ) {
// Override the console defaults by creating an anonymous namespace
// that returns a new function that is used instead of the existing
// function.
console [ m ] = ( function ( i ) {
2014-05-18 22:32:33 -05:00
// Check if dir up to date
var diso = moment ( ) . isoWeekday ( ) ;
if ( dayiso != diso ) {
fpath = logpath = createdir ( ) ;
dayiso = diso ;
}
2014-01-23 17:17:54 -06:00
// Important to overload instead of override. This way we can
// actually reuse the old function.
var _backup = console [ i ] ;
return function ( ) {
// We need to apply any formatting from the variables.
// Notice we don't know the number of arguments, so we
// use the 'arguments' variable instead.
2014-05-18 22:32:33 -05:00
var utfs = arguments . length == 1 && typeof arguments [ 0 ] === 'object' ? JSON . stringify ( arguments [ 0 ] , null , 4 ) : util . format . apply ( util , arguments ) . trim ( )
2014-01-23 17:17:54 -06:00
// Moment.js is a great time library for Node.js
, mtime = moment ( ) . format ( 'MMMM Do YYYY, h:mm:ss A' )
// Used to show where the tags are to be placed.
// I.e. [Memache] Message goes here.
// Coldex holds the index of the first ']'
, coldex = 0
// The file we are appending to changes everyday since
// its directory changes by date.
, file = path . join ( fpath , 'app.' + i )
// Default file type
, options = { encoding : 'utf8' }
, fullIndent = _sps ( loggers . settings . preIndent + loggers . settings . maxTagLength )
, defaultTagPostIndent = _sps ( loggers . settings . maxTagLength - loggers . settings . defaultTag . length )
, temp = ''
, preIndent = _sps ( loggers . settings . preIndent ) ;
2014-05-18 22:32:33 -05:00
2014-01-23 17:17:54 -06:00
// Check with logger settings to see if the message should
// be outputed to file. Note: Don't append empty lines!
2014-05-18 22:32:33 -05:00
if ( loggers . types [ i ] . file && utfs != '' )
// For large data, block the process when outputting.
fs . appendFileSync ( file , mtime + loggers . settings . divider +
utfs . stripColors . replace ( /\n/g , '\n' + mtime + loggers . settings . divider ) + "\n" , options , function ( err ) { } ) ;
2014-01-23 17:17:54 -06:00
// Check whether the message should be outputed to console.
// Usually, long strings are marked as output ONLY to file
// and NOT to console. Short and important messages are
// usually outputed to BOTH.
if ( loggers . types [ i ] . console ) {
// See if a tag exists and if so, colorize it.
if ( ( coldex = utfs . indexOf ( ']' ) + 1 ) <= loggers . settings . maxTagLength && utfs . indexOf ( ']' ) > - 1 )
_backup ( preIndent + utfs . substring ( 0 , coldex ) [ i ] + ( temp = _sps ( loggers . settings . maxTagLength - coldex ) ) + utfs . substring ( coldex ) . replace ( /\n/g , '\n' + preIndent + utfs . substring ( 0 , coldex ) [ i ] + temp ) ) ;
// No tag? Just pring the whole message out.
else if ( utfs . trim ( ) != '' )
_backup ( ( temp = preIndent + loggers . settings . defaultTag [ i ] + defaultTagPostIndent ) + utfs . replace ( /\n/g , '\n' + temp ) ) ;
// If the content is just a linebreak or some spaces, just output as it is.
else
_backup ( utfs ) ;
}
}
} ) ( m ) ;
}
// String.prototype with basic methods.
// Override default styles
require ( 'colors' ) . setTheme ( loggers . colors ) ;
// Basic banner indicating its Turredo output in the command prompt.
// Just for fancies and it helps keep track the number of restarts.
console . info ( '\n' ) ;
for ( var i in loggers . types ) {
2014-05-18 22:32:33 -05:00
console [ i ] ( '[' + APP _NAME + ']' + 'Started - console.%s' , i . toUpperCase ( ) ) ;
2014-01-23 17:17:54 -06:00
}
console . info ( '\n' ) ;
}
// Express middleware logger.
var logger = function ( req , res , next ) {
// Important to see who is accessing what and when
// Should be a printout of every access and its respective data.
2014-05-18 22:32:33 -05:00
console . info ( '[%s]%s | %s %s %s' , "Express"
, req . ip . red
, req . method . green
, req . url . grey
2014-01-23 17:17:54 -06:00
, ( /mobile/i . test ( req . headers [ 'user-agent' ] ) ? 'MOBILE' : 'DESKTOP' ) . yellow ) ;
// Continue with the next process in the Express framework
next ( ) ;
}
2014-05-18 22:32:33 -05:00
var htmltemplate = "" ;
var css = { } ;
css [ 'html,body' ] = 'margin:0; border:none;float:none;display:block;padding:0;font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;background:#1c262f;overflow:hidden;' ;
css [ 'div' ] = 'font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;font-size:11px;' ;
css [ 'html' ] = 'background:#2A3946;padding:0;padding-left:50px;'
css [ 'body' ] = 'border-left: 1px solid rgba(255, 255, 255, 0.12);' ;
css [ '.log-time' ] = 'background: none;color: rgba(255, 255, 255, 0.24);padding:2px 5px;margin-right:2px;margin-left:-1px;font-size:11px;' ;
css [ '.log-type' ] = 'background: #633E3E;color: #C20404;padding:2px 5px;margin-right:2px;font-size:11px;' ;
css [ '.log-line' ] = 'height:auto;line-height:15px;color:#BEBEBE;font-size:11px;'
css [ '.button, .selected' ] = "font-family:Consolas,Menlo,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New,monospace,serif;background:#2C3338;text-align:center;width:100%;line-height:35px;height:35px;margin-bottom:5px;box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.11);"
css [ '.selected' ] = "background:#4D5961;"
css [ 'a' ] = "background:none;text-decoration:none;font-size: 11px;color: #C2C2C2;padding: 10px;"
htmltemplate += "<head><title>TITLE</title><style>"
for ( var i in css ) htmltemplate += i + "{" + css [ i ] + "}" ;
htmltemplate += "</style></head>" ;
var buttons = '<div style = "position:fixed;top:5px;left:5px;width:40px;height:100px;">' +
'<div class="button info_selected"><a href="log?type=info">I</a></div>' +
'<div class="button log_selected"><a href="log?type=log">L</a></div>' +
'<div class="button error_selected"><a href="log?type=error">E</a></div>' +
'<div class="button warn_selected"><a href="log?type=warn">W</a></div>' +
'<div class="button realtime_selected"><a href="log?type=realtime">Re</a></div>' +
'<div class="button high_selected"><a href="log?type=high">Hi</a></div>' +
'<div class="button normal_selected"><a href="log?type=normal">No</a></div>' +
'<div class="button low_selected"><a href="log?type=low">Lo</a></div>' +
'</div>'
htmltemplate += '<body style="position:relative;"><div style="position:absolute;left:0;top:0;bottom:0;right:0;"><div style="width:100%;height:100%;overflow:auto;"><div style="width:100%;height:auto;">CONTENT</div></div></div>' + buttons + '</body>' ;
htmltemplate = "<html>" + htmltemplate + "</html>" ;
var divRegex = loggers . settings . divider . replace ( /([\||\$|\^|\?|\[|\]|\)|\(|\{|\}])/g , '\\$1' ) ;
var regA = new RegExp ( '^(.*?)(' + divRegex + ")" , 'mg' ) ;
var regB = new RegExp ( '^(.*?)' + divRegex + '\\s{0,}\\[(.*?)\\](.*?)$' , 'gm' )
var regC = new RegExp ( '^(.*?)' + divRegex , 'mg' ) ;
var getlog = function ( req , res ) {
var type = req . param ( 'type' ) ;
type = type ? type : "log" ;
var contents = "No log found" ;
fs . readFile ( logpath + "/app." + type , 'utf8' , function ( err , data ) {
if ( ! err ) contents = data ;
// contents = contents.replace(/^(.*?)#\|#/mg, '<span class = "log-time">$1</span>#\|#')
contents = contents . replace ( / /g , ' ' )
contents = contents . replace ( regA , '<span class = "log-time">$1</span>$2' ) ;
contents = contents . replace ( regB , '$1<span class = "log-type">$2</span>$3' ) ;
contents = contents . replace ( regC , '$1' )
contents = contents . replace ( /^(.*?)$/mg , '<div class = "log-line">$1</div>' )
var response = htmltemplate . replace ( type + '_' , '' ) . replace ( "CONTENT" , contents ) . replace ( "TITLE" , APP _NAME + " - " + type ) ;
res . send ( response ) ;
} ) ;
}
exports . init = overload ;
2014-01-23 17:17:54 -06:00
2014-05-18 22:32:33 -05:00
exports . express = {
'logger' : logger ,
'getlog' : getlog
}