11'use strict' ;
22
33const fs = require ( 'fs' ) ;
4+ const { EventEmitter } = require ( 'events' ) ;
45const _ = require ( 'lodash' ) ;
6+ const Q = require ( 'q' ) ;
57const Docker = require ( 'dockerode' ) ;
68const DockerEvents = require ( 'docker-events' ) ;
79const CFError = require ( 'cf-errors' ) ;
@@ -12,15 +14,16 @@ const ContainerHandlingStatus = require('./enums').ContainerHandlingStatus;
1214const ContainerLogger = require ( './ContainerLogger' ) ;
1315const { TaskLogger } = require ( '@codefresh-io/task-logger' ) ;
1416
15-
16- const initialState = { status : 'init' , lastLogsDate : Date . now ( ) , failedHealthChecks : [ ] , restartCounter : 0 , containers : { } } ;
17+ const initialState = { pid : process . pid , status : 'init' , lastLogsDate : new Date ( ) , failedHealthChecks : [ ] , restartCounter : 0 , containers : { } } ;
1718class Logger {
1819
1920 constructor ( {
2021 loggerId,
2122 taskLoggerConfig,
2223 findExistingContainers,
23- logSizeLimit
24+ logSizeLimit,
25+ buildFinishedPromise,
26+ showProgress,
2427 } ) {
2528 this . taskLoggerConfig = taskLoggerConfig ;
2629 this . loggerId = loggerId ;
@@ -29,6 +32,10 @@ class Logger {
2932 this . containerLoggers = [ ] ;
3033 this . logSize = 0 ;
3134 this . taskLogger = undefined ;
35+ this . buildFinishedPromise = buildFinishedPromise || Q . resolve ( ) ;
36+ this . finishedContainers = 0 ;
37+ this . finishedContainersEmitter = new EventEmitter ( ) ;
38+ this . showProgress = showProgress ;
3239
3340 let dockerSockPath ;
3441 if ( fs . existsSync ( '/var/run/codefresh/docker.sock' ) ) {
@@ -43,6 +50,8 @@ class Logger {
4350 socketPath : dockerSockPath ,
4451 } ) ;
4552 this . _readState ( ) ;
53+ this . _handleBuildFinished ( ) ;
54+ this . _updateStateInterval = setInterval ( this . _updateStateFile . bind ( this ) , 1000 ) ;
4655 }
4756
4857 /**
@@ -70,6 +79,7 @@ class Logger {
7079
7180 TaskLogger ( this . taskLoggerConfig . task , this . taskLoggerConfig . opts )
7281 . then ( ( taskLogger ) => {
82+ this . taskLogger = taskLogger ;
7383 taskLogger . on ( 'error' , ( err ) => {
7484 logger . error ( err . stack ) ;
7585 } ) ;
@@ -81,12 +91,16 @@ class Logger {
8191 } else {
8292 this . state . healthCheckStatus = status ;
8393 }
94+
8495 this . _writeNewState ( ) ;
8596 } ) ;
86-
87- this . taskLogger = taskLogger ;
97+ taskLogger . on ( 'flush' , ( ) => {
98+ this . _updateMissingLogs ( ) ;
99+ this . _updateLastLoggingDate ( ) ;
100+ } ) ;
101+ this . state . logsStatus = this . taskLogger . getStatus ( ) ;
88102 logger . info ( `taskLogger successfully created` ) ;
89-
103+
90104 this . _listenForNewContainers ( ) ;
91105
92106 this . state . status = 'ready' ;
@@ -108,8 +122,9 @@ class Logger {
108122 _readState ( ) {
109123 const filePath = `${ __dirname } /state.json` ;
110124 if ( fs . existsSync ( filePath ) ) {
111- this . state = _ . omit ( JSON . parse ( fs . readFileSync ( filePath , 'utf8' ) , 'containers' ) ) ;
125+ this . state = _ . omit ( JSON . parse ( fs . readFileSync ( filePath , 'utf8' ) , [ 'containers' , 'pid' ] ) ) ;
112126 this . state . containers = { } ;
127+ this . state . pid = process . pid ;
113128 let restartCounter = _ . get ( this . state , 'restartCounter' , 0 ) ;
114129 restartCounter ++ ;
115130 this . state . restartCounter = restartCounter ;
@@ -143,10 +158,9 @@ class Logger {
143158 } else if ( ! disableLog ) {
144159 logger . info ( `State: ${ currentState } updated and written to file: ${ filePath } ` ) ;
145160 }
146- } ) ;
161+ } ) ;
147162 }
148163
149-
150164 logLimitExceeded ( ) {
151165 // TODO in the future when we allow a workflow to use multuple dinds, this will not be correct
152166 // we need to get the total size of logs from all dinds
@@ -238,7 +252,7 @@ class Logger {
238252 } ) ;
239253 this . containerLoggers . push ( containerLogger ) ;
240254 containerLogger . on ( 'message.logged' , this . _updateTotalLogSize . bind ( this ) ) ;
241- containerLogger . on ( 'message.logged ', this . _updateLastLoggingDate . bind ( this ) ) ;
255+ containerLogger . once ( 'end ', this . _handleContainerStreamEnd . bind ( this ) ) ;
242256
243257 containerLogger . start ( )
244258 . done ( ( ) => {
@@ -254,14 +268,33 @@ class Logger {
254268 } ) ;
255269 }
256270
271+ _updateMissingLogs ( ) {
272+ const resolvedCalls = _ . get ( this , 'state.logsStatus.resolvedCalls' , 0 ) ;
273+ const writeCalls = _ . get ( this , 'state.logsStatus.writeCalls' , 0 ) ;
274+ const rejectedCalls = _ . get ( this , 'state.logsStatus.rejectedCalls' , 0 ) ;
275+
276+ _ . set ( this , 'state.logsStatus.missingLogs' , writeCalls - resolvedCalls - rejectedCalls ) ;
277+ }
278+
257279 _updateTotalLogSize ( ) {
258280 this . logSize = this . _getTotalLogSize ( ) ;
259281 this . taskLogger . setLogSize ( this . logSize ) ;
260282 }
261283
262284 _updateLastLoggingDate ( ) {
263- this . state . lastLogsDate = Date . now ( ) ;
264- this . _writeNewState ( true ) ;
285+ this . state . lastLogsDate = new Date ( ) ;
286+ }
287+
288+ _updateStateFile ( ) {
289+ if ( this . state . status === 'done' ) {
290+ clearInterval ( this . _updateStateInterval ) ;
291+ } else {
292+ this . _writeNewState ( true ) ;
293+
294+ if ( this . showProgress ) {
295+ logger . debug ( `logger progress update: ${ JSON . stringify ( this . state . logsStatus ) } ` ) ;
296+ }
297+ }
265298 }
266299
267300 /**
@@ -304,6 +337,42 @@ class Logger {
304337 } ) ;
305338 }
306339
340+ _handleContainerStreamEnd ( ) {
341+ this . finishedContainers ++ ;
342+ this . finishedContainersEmitter . emit ( 'end' ) ;
343+ }
344+
345+ // do not call before build is finished
346+ _awaitAllStreamsClosed ( ) {
347+ const deferred = Q . defer ( ) ;
348+ this . _checkAllStreamsClosed ( deferred ) ;
349+ this . finishedContainersEmitter . on ( 'end' , this . _checkAllStreamsClosed . bind ( this , deferred ) ) ;
350+ return deferred . promise ;
351+ }
352+
353+ _checkAllStreamsClosed ( deferred ) {
354+ if ( this . finishedContainers === this . containerLoggers . length ) {
355+ deferred . resolve ( ) ;
356+ }
357+ }
358+
359+ _handleBuildFinished ( ) {
360+ this . buildFinishedPromise
361+ . then ( ( ) => {
362+ logger . info ( '=== build is finished ===' ) ;
363+ return this . _awaitAllStreamsClosed ( ) ;
364+ } )
365+ . then ( ( ) => {
366+ logger . info ( '=== all streams have been closed ===' ) ;
367+ return this . taskLogger . awaitLogsFlushed ( ) ;
368+ } )
369+ . then ( ( ) => {
370+ logger . info ( '=== All logs flushed. Container logger finished. ===' ) ;
371+ this . state . logsStatus = this . taskLogger . getStatus ( ) ;
372+ this . state . status = 'done' ;
373+ this . _writeNewState ( ) ;
374+ } ) ;
375+ }
307376}
308377
309378module . exports = Logger ;
0 commit comments