@@ -148,3 +148,155 @@ DailyRotateFile.prototype.close = function () {
148148 } ) ;
149149 }
150150} ;
151+
152+ DailyRotateFile . prototype . query = function ( options , callback ) {
153+ if ( typeof options === 'function' ) {
154+ callback = options ;
155+ options = { } ;
156+ }
157+
158+ if ( ! this . options . json ) {
159+ throw new Error ( 'query() may not be used without the json option being set to true' ) ;
160+ }
161+
162+ if ( ! this . filename ) {
163+ throw new Error ( 'query() may not be used when initializing with a stream' ) ;
164+ }
165+
166+ var self = this ;
167+ var results = [ ] ;
168+ options = options || { } ;
169+
170+ // limit
171+ options . rows = options . rows || options . limit || 10 ;
172+
173+ // starting row offset
174+ options . start = options . start || 0 ;
175+
176+ // now
177+ options . until = options . until || new Date ;
178+ if ( typeof options . until !== 'object' ) {
179+ options . until = new Date ( options . until ) ;
180+ }
181+
182+ // now - 24
183+ options . from = options . from || ( options . until - ( 24 * 60 * 60 * 1000 ) ) ;
184+ if ( typeof options . from !== 'object' ) {
185+ options . from = new Date ( options . from ) ;
186+ }
187+
188+ // 'asc' or 'desc'
189+ options . order = options . order || 'desc' ;
190+
191+ var logFiles = ( function ( ) {
192+ var fileRegex = new RegExp ( self . filename . replace ( '%DATE%' , '.*' ) , 'i' ) ;
193+ return fs . readdirSync ( self . dirname ) . filter ( function ( file ) {
194+ return path . basename ( file ) . match ( fileRegex ) ;
195+ } ) ;
196+ } ) ( ) ;
197+
198+ if ( logFiles . length === 0 && callback ) {
199+ callback ( null , results ) ;
200+ }
201+
202+ ( function processLogFile ( file ) {
203+ if ( ! file ) {
204+ return ;
205+ }
206+
207+ var logFile = path . join ( self . dirname , file ) ;
208+ var buff = '' ;
209+
210+ var stream ;
211+
212+ if ( file . endsWith ( '.gz' ) ) {
213+ stream = new PassThrough ( ) ;
214+ fs . createReadStream ( logFile ) . pipe ( zlib . createGunzip ( ) ) . pipe ( stream ) ;
215+ } else {
216+ stream = fs . createReadStream ( logFile , {
217+ encoding : 'utf8'
218+ } ) ;
219+ }
220+
221+ stream . on ( 'error' , function ( err ) {
222+ if ( stream . readable ) {
223+ stream . destroy ( ) ;
224+ }
225+
226+ if ( ! callback ) {
227+ return ;
228+ }
229+
230+ return err . code === 'ENOENT' ? callback ( null , results ) : callback ( err ) ;
231+ } ) ;
232+
233+ stream . on ( 'data' , function ( data ) {
234+ data = ( buff + data ) . split ( / \n + / ) ;
235+ var l = data . length - 1 ;
236+
237+ for ( var i = 0 ; i < l ; i ++ ) {
238+ add ( data [ i ] ) ;
239+ }
240+
241+ buff = data [ l ] ;
242+ } ) ;
243+
244+ stream . on ( 'end' , function ( ) {
245+ if ( buff ) {
246+ add ( buff , true ) ;
247+ }
248+
249+ if ( logFiles . length ) {
250+ processLogFile ( logFiles . shift ( ) ) ;
251+ } else if ( callback ) {
252+ results . sort ( function ( a , b ) {
253+ var d1 = new Date ( a . timestamp ) . getTime ( ) ;
254+ var d2 = new Date ( b . timestamp ) . getTime ( ) ;
255+
256+ return d1 > d2 ? 1 : d1 < d2 ? - 1 : 0 ;
257+ } ) ;
258+
259+ if ( options . order === 'desc' ) {
260+ results = results . reverse ( ) ;
261+ }
262+
263+ var start = options . start || 0 ;
264+ var limit = options . limit || results . length ;
265+
266+ results = results . slice ( start , start + limit ) ;
267+
268+ if ( options . fields ) {
269+ results = results . map ( function ( log ) {
270+ var obj = { } ;
271+ options . fields . forEach ( function ( key ) {
272+ obj [ key ] = log [ key ] ;
273+ } ) ;
274+ return obj ;
275+ } ) ;
276+ }
277+
278+ callback ( null , results ) ;
279+ }
280+ } ) ;
281+
282+ function add ( buff , attempt ) {
283+ try {
284+ var log = JSON . parse ( buff ) ;
285+ if ( ! log || typeof log !== 'object' ) {
286+ return ;
287+ }
288+
289+ var time = new Date ( log . timestamp ) ;
290+ if ( ( options . from && time < options . from ) || ( options . until && time > options . until ) ) {
291+ return ;
292+ }
293+
294+ results . push ( log ) ;
295+ } catch ( e ) {
296+ if ( ! attempt ) {
297+ stream . emit ( 'error' , e ) ;
298+ }
299+ }
300+ }
301+ } ) ( logFiles . shift ( ) ) ;
302+ } ;
0 commit comments