1
1
'use strict' ;
2
2
3
3
const fs = require ( 'fs' ) ;
4
+ const { EventEmitter } = require ( 'events' ) ;
4
5
const _ = require ( 'lodash' ) ;
6
+ const Q = require ( 'q' ) ;
5
7
const Docker = require ( 'dockerode' ) ;
6
8
const DockerEvents = require ( 'docker-events' ) ;
7
9
const CFError = require ( 'cf-errors' ) ;
@@ -12,15 +14,16 @@ const ContainerHandlingStatus = require('./enums').ContainerHandlingStatus;
12
14
const ContainerLogger = require ( './ContainerLogger' ) ;
13
15
const { TaskLogger } = require ( '@codefresh-io/task-logger' ) ;
14
16
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 : { } } ;
17
18
class Logger {
18
19
19
20
constructor ( {
20
21
loggerId,
21
22
taskLoggerConfig,
22
23
findExistingContainers,
23
- logSizeLimit
24
+ logSizeLimit,
25
+ buildFinishedPromise,
26
+ showProgress,
24
27
} ) {
25
28
this . taskLoggerConfig = taskLoggerConfig ;
26
29
this . loggerId = loggerId ;
@@ -29,6 +32,10 @@ class Logger {
29
32
this . containerLoggers = [ ] ;
30
33
this . logSize = 0 ;
31
34
this . taskLogger = undefined ;
35
+ this . buildFinishedPromise = buildFinishedPromise || Q . resolve ( ) ;
36
+ this . finishedContainers = 0 ;
37
+ this . finishedContainersEmitter = new EventEmitter ( ) ;
38
+ this . showProgress = showProgress ;
32
39
33
40
let dockerSockPath ;
34
41
if ( fs . existsSync ( '/var/run/codefresh/docker.sock' ) ) {
@@ -43,6 +50,8 @@ class Logger {
43
50
socketPath : dockerSockPath ,
44
51
} ) ;
45
52
this . _readState ( ) ;
53
+ this . _handleBuildFinished ( ) ;
54
+ this . _updateStateInterval = setInterval ( this . _updateStateFile . bind ( this ) , 1000 ) ;
46
55
}
47
56
48
57
/**
@@ -70,6 +79,7 @@ class Logger {
70
79
71
80
TaskLogger ( this . taskLoggerConfig . task , this . taskLoggerConfig . opts )
72
81
. then ( ( taskLogger ) => {
82
+ this . taskLogger = taskLogger ;
73
83
taskLogger . on ( 'error' , ( err ) => {
74
84
logger . error ( err . stack ) ;
75
85
} ) ;
@@ -81,12 +91,16 @@ class Logger {
81
91
} else {
82
92
this . state . healthCheckStatus = status ;
83
93
}
94
+
84
95
this . _writeNewState ( ) ;
85
96
} ) ;
86
-
87
- this . taskLogger = taskLogger ;
97
+ taskLogger . on ( 'flush' , ( ) => {
98
+ this . _updateMissingLogs ( ) ;
99
+ this . _updateLastLoggingDate ( ) ;
100
+ } ) ;
101
+ this . state . logsStatus = this . taskLogger . getStatus ( ) ;
88
102
logger . info ( `taskLogger successfully created` ) ;
89
-
103
+
90
104
this . _listenForNewContainers ( ) ;
91
105
92
106
this . state . status = 'ready' ;
@@ -108,8 +122,9 @@ class Logger {
108
122
_readState ( ) {
109
123
const filePath = `${ __dirname } /state.json` ;
110
124
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' ] ) ) ;
112
126
this . state . containers = { } ;
127
+ this . state . pid = process . pid ;
113
128
let restartCounter = _ . get ( this . state , 'restartCounter' , 0 ) ;
114
129
restartCounter ++ ;
115
130
this . state . restartCounter = restartCounter ;
@@ -143,10 +158,9 @@ class Logger {
143
158
} else if ( ! disableLog ) {
144
159
logger . info ( `State: ${ currentState } updated and written to file: ${ filePath } ` ) ;
145
160
}
146
- } ) ;
161
+ } ) ;
147
162
}
148
163
149
-
150
164
logLimitExceeded ( ) {
151
165
// TODO in the future when we allow a workflow to use multuple dinds, this will not be correct
152
166
// we need to get the total size of logs from all dinds
@@ -238,7 +252,7 @@ class Logger {
238
252
} ) ;
239
253
this . containerLoggers . push ( containerLogger ) ;
240
254
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 ) ) ;
242
256
243
257
containerLogger . start ( )
244
258
. done ( ( ) => {
@@ -254,14 +268,33 @@ class Logger {
254
268
} ) ;
255
269
}
256
270
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
+
257
279
_updateTotalLogSize ( ) {
258
280
this . logSize = this . _getTotalLogSize ( ) ;
259
281
this . taskLogger . setLogSize ( this . logSize ) ;
260
282
}
261
283
262
284
_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
+ }
265
298
}
266
299
267
300
/**
@@ -304,6 +337,42 @@ class Logger {
304
337
} ) ;
305
338
}
306
339
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
+ }
307
376
}
308
377
309
378
module . exports = Logger ;
0 commit comments