11var layouts = require ( '../layouts' )
2+ , path = require ( 'path' )
23, fs = require ( 'fs' ) ;
34
45/**
@@ -8,46 +9,69 @@ var layouts = require('../layouts')
89 * @param layout a function that takes a logevent and returns a string (defaults to basicLayout).
910 * @param logSize - the maximum size (in bytes) for a log file, if not provided then logs won't be rotated.
1011 * @param numBackups - the number of log files to keep after logSize has been reached (default 5)
11- * @param filePollInterval - the time in seconds between file size checks (default 30s)
1212 */
13- function fileAppender ( file , layout , logSize , numBackups , filePollInterval ) {
13+ function fileAppender ( file , layout , logSize , numBackups ) {
14+ var bytesWritten = 0 ;
15+ file = path . normalize ( file ) ;
1416 layout = layout || layouts . basicLayout ;
1517 numBackups = numBackups === undefined ? 5 : numBackups ;
1618 //there has to be at least one backup if logSize has been specified
1719 numBackups = numBackups === 0 ? 1 : numBackups ;
18- filePollInterval = filePollInterval * 1000 || 30000 ;
1920
2021 function setupLogRolling ( ) {
21- fs . watchFile (
22- file ,
23- {
24- persistent : false ,
25- interval : filePollInterval
26- } ,
27- function ( curr , prev ) {
28- if ( curr . size >= logSize ) {
29- rollThatLog ( ) ;
30- }
22+ try {
23+ var stat = fs . statSync ( file ) ;
24+ bytesWritten = stat . size ;
25+ if ( bytesWritten >= logSize ) {
26+ rollThatLog ( ) ;
3127 }
32- ) ;
28+ } catch ( e ) {
29+ //file does not exist
30+ bytesWritten = 0 ;
31+ }
3332 }
3433
3534 function rollThatLog ( ) {
36- //roll the backups (rename file.n-1 to file.n, where n <= numBackups)
37- for ( var i = numBackups ; i > 0 ; i -- ) {
38- if ( i > 1 ) {
39- if ( fileExists ( file + '.' + ( i - 1 ) ) ) {
40- fs . renameSync ( file + '.' + ( i - 1 ) , file + '.' + i ) ;
41- }
35+ function index ( filename ) {
36+ return parseInt ( filename . substring ( ( path . basename ( file ) + '.' ) . length ) , 10 ) || 0 ;
37+ }
38+
39+ var nameMatcher = new RegExp ( '^' + path . basename ( file ) ) ;
40+ function justTheLogFiles ( item ) {
41+ return nameMatcher . test ( item ) ;
42+ }
43+
44+ function byIndex ( a , b ) {
45+ if ( index ( a ) > index ( b ) ) {
46+ return 1 ;
47+ } else if ( index ( a ) < index ( b ) ) {
48+ return - 1 ;
4249 } else {
43- fs . renameSync ( file , file + '.1' ) ;
50+ return 0 ;
4451 }
4552 }
53+
54+ function increaseFileIndex ( fileToRename ) {
55+ var idx = index ( fileToRename ) ;
56+ if ( idx < numBackups ) {
57+ fs . renameSync ( path . join ( path . dirname ( file ) , fileToRename ) , file + '.' + ( idx + 1 ) ) ;
58+ }
59+ }
60+
61+ //roll the backups (rename file.n to file.n+1, where n <= numBackups)
62+ fs . readdirSync ( path . dirname ( file ) )
63+ . filter ( justTheLogFiles )
64+ . sort ( byIndex )
65+ . reverse ( )
66+ . forEach ( increaseFileIndex ) ;
67+
4668 //let's make a new file
4769 var newLogFileFD = fs . openSync ( file , 'a' , 0644 )
4870 , oldLogFileFD = logFile . fd ;
4971 logFile . fd = newLogFileFD ;
5072 fs . close ( oldLogFileFD ) ;
73+ //reset the counter
74+ bytesWritten = 0 ;
5175 }
5276
5377 function fileExists ( filename ) {
@@ -62,26 +86,23 @@ function fileAppender (file, layout, logSize, numBackups, filePollInterval) {
6286 function openTheStream ( ) {
6387 var stream = fs . createWriteStream ( file , { flags : 'a' , mode : 0644 , encoding : 'utf8' } ) ;
6488 stream . on ( "open" , function ( ) {
65- canWrite = true ;
66- while ( logEventBuffer . length > 0 && canWrite ) {
67- canWrite = writeToLog ( logEventBuffer . shift ( ) ) ;
89+ if ( logEventBuffer . length > 0 ) {
90+ writeToLog ( logEventBuffer . shift ( ) ) ;
6891 }
6992 } ) ;
7093 stream . on ( "error" , function ( err ) {
71- console . error ( "log4js.fileAppender - Error happened " , err ) ;
94+ console . error ( "log4js.fileAppender - Writing to file %s, error happened " , file , err ) ;
7295 } ) ;
7396 stream . on ( "drain" , function ( ) {
74- canWrite = true ;
75- while ( logEventBuffer . length > 0 && canWrite ) {
76- canWrite = writeToLog ( logEventBuffer . shift ( ) ) ;
97+ if ( logEventBuffer . length > 0 ) {
98+ writeToLog ( logEventBuffer . shift ( ) ) ;
7799 }
78100 } ) ;
79101 return stream ;
80102 }
81103
82104
83105 var logEventBuffer = [ ]
84- , canWrite = false
85106 , logFile = openTheStream ( ) ;
86107
87108 if ( logSize > 0 ) {
@@ -95,17 +116,17 @@ function fileAppender (file, layout, logSize, numBackups, filePollInterval) {
95116 } ) ;
96117
97118 function writeToLog ( loggingEvent ) {
98- return logFile . write ( layout ( loggingEvent ) + '\n' , "utf8" ) ;
119+ var logMessage = layout ( loggingEvent ) + '\n' ;
120+ //not entirely accurate, but it'll do.
121+ bytesWritten += logMessage . length ;
122+ logFile . write ( logMessage , "utf8" ) ;
123+ if ( bytesWritten >= logSize ) {
124+ rollThatLog ( ) ;
125+ }
99126 }
100127
101128 return function ( loggingEvent ) {
102- //because the log stream is opened asynchronously, we don't want to write
103- //until it is ready.
104- if ( canWrite ) {
105- canWrite = writeToLog ( loggingEvent ) ;
106- } else {
107- logEventBuffer . push ( loggingEvent ) ;
108- }
129+ logEventBuffer . push ( loggingEvent ) ;
109130 } ;
110131}
111132
@@ -114,7 +135,7 @@ function configure(config) {
114135 if ( config . layout ) {
115136 layout = layouts . layout ( config . layout . type , config . layout ) ;
116137 }
117- return fileAppender ( config . filename , layout , config . maxLogSize , config . backups , config . pollInterval ) ;
138+ return fileAppender ( config . filename , layout , config . maxLogSize , config . backups ) ;
118139}
119140
120141exports . name = "file" ;
0 commit comments