11import * as util from 'util' ;
22import * as cxapi from '@aws-cdk/cx-api' ;
33import * as chalk from 'chalk' ;
4- import { info , error } from '../../logging' ;
4+ import * as uuid from 'uuid' ;
5+ import { IO } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io' ;
6+ import type { CloudWatchLogEvent } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io' ;
7+ import { IoHelper } from '../../../../@aws-cdk/tmp-toolkit-helpers/src/api/io/private' ;
58import { flatten } from '../../util' ;
69import type { SDK } from '../aws-auth' ;
710
8- /**
9- * After reading events from all CloudWatch log groups
10- * how long should we wait to read more events.
11- *
12- * If there is some error with reading events (i.e. Throttle)
13- * then this is also how long we wait until we try again
14- */
15- const SLEEP = 2_000 ;
16-
17- /**
18- * Represents a CloudWatch Log Event that will be
19- * printed to the terminal
20- */
21- interface CloudWatchLogEvent {
22- /**
23- * The log event message
24- */
25- readonly message : string ;
26-
27- /**
28- * The name of the log group
29- */
30- readonly logGroupName : string ;
31-
32- /**
33- * The time at which the event occurred
34- */
35- readonly timestamp : Date ;
36- }
37-
3811/**
3912 * Configuration tracking information on the log groups that are
4013 * being monitored
@@ -54,6 +27,20 @@ interface LogGroupsAccessSettings {
5427 readonly logGroupsStartTimes : { [ logGroupName : string ] : number } ;
5528}
5629
30+ export interface CloudWatchLogEventMonitorProps {
31+ /**
32+ * The IoHost used for messaging
33+ */
34+ readonly ioHelper : IoHelper ;
35+
36+ /**
37+ * The time from which we start reading log messages
38+ *
39+ * @default - now
40+ */
41+ readonly startTime ?: Date ;
42+ }
43+
5744export class CloudWatchLogEventMonitor {
5845 /**
5946 * Determines which events not to display
@@ -65,18 +52,36 @@ export class CloudWatchLogEventMonitor {
6552 */
6653 private readonly envsLogGroupsAccessSettings = new Map < string , LogGroupsAccessSettings > ( ) ;
6754
68- private active = false ;
55+ /**
56+ * After reading events from all CloudWatch log groups
57+ * how long should we wait to read more events.
58+ *
59+ * If there is some error with reading events (i.e. Throttle)
60+ * then this is also how long we wait until we try again
61+ */
62+ private readonly pollingInterval : number = 2_000 ;
63+
64+ public monitorId ?: string ;
65+ private readonly ioHelper : IoHelper ;
6966
70- constructor ( startTime ?: Date ) {
71- this . startTime = startTime ?. getTime ( ) ?? Date . now ( ) ;
67+ constructor ( props : CloudWatchLogEventMonitorProps ) {
68+ this . startTime = props . startTime ?. getTime ( ) ?? Date . now ( ) ;
69+ this . ioHelper = props . ioHelper ;
7270 }
7371
7472 /**
7573 * resume reading/printing events
7674 */
77- public activate ( ) : void {
78- this . active = true ;
79- this . scheduleNextTick ( 0 ) ;
75+ public async activate ( ) : Promise < void > {
76+ this . monitorId = uuid . v4 ( ) ;
77+
78+ await this . ioHelper . notify ( IO . CDK_TOOLKIT_I5032 . msg ( 'Start monitoring log groups' , {
79+ monitor : this . monitorId ,
80+ logGroupNames : this . logGroupNames ( ) ,
81+ } ) ) ;
82+
83+ await this . tick ( ) ;
84+ this . scheduleNextTick ( ) ;
8085 }
8186
8287 /**
@@ -88,9 +93,16 @@ export class CloudWatchLogEventMonitor {
8893 * Also resets the start time to be when the new deployment was triggered
8994 * and clears the list of tracked log groups
9095 */
91- public deactivate ( ) : void {
92- this . active = false ;
96+ public async deactivate ( ) : Promise < void > {
97+ const oldMonitorId = this . monitorId ! ;
98+ this . monitorId = undefined ;
9399 this . startTime = Date . now ( ) ;
100+
101+ await this . ioHelper . notify ( IO . CDK_TOOLKIT_I5034 . msg ( 'Stopped monitoring log groups' , {
102+ monitor : oldMonitorId ,
103+ logGroupNames : this . logGroupNames ( ) ,
104+ } ) ) ;
105+
94106 this . envsLogGroupsAccessSettings . clear ( ) ;
95107 }
96108
@@ -119,27 +131,41 @@ export class CloudWatchLogEventMonitor {
119131 } ) ;
120132 }
121133
122- private scheduleNextTick ( sleep : number ) : void {
123- setTimeout ( ( ) => void this . tick ( ) , sleep ) ;
134+ private logGroupNames ( ) : string [ ] {
135+ return Array . from ( this . envsLogGroupsAccessSettings . values ( ) ) . flatMap ( ( settings ) => Object . keys ( settings . logGroupsStartTimes ) ) ;
136+ }
137+
138+ private scheduleNextTick ( ) : void {
139+ if ( ! this . monitorId ) {
140+ return ;
141+ }
142+
143+ setTimeout ( ( ) => void this . tick ( ) , this . pollingInterval ) ;
124144 }
125145
126146 private async tick ( ) : Promise < void > {
127147 // excluding from codecoverage because this
128148 // doesn't always run (depends on timing)
129- /* istanbul ignore next */
130- if ( ! this . active ) {
149+ /* c8 ignore next */
150+ if ( ! this . monitorId ) {
131151 return ;
132152 }
153+
133154 try {
134155 const events = flatten ( await this . readNewEvents ( ) ) ;
135- events . forEach ( ( event ) => {
136- this . print ( event ) ;
137- } ) ;
138- } catch ( e ) {
139- error ( 'Error occurred while monitoring logs: %s' , e ) ;
156+ for ( const event of events ) {
157+ await this . print ( event ) ;
158+ }
159+
160+ // We might have been stop()ped while the network call was in progress.
161+ if ( ! this . monitorId ) {
162+ return ;
163+ }
164+ } catch ( e : any ) {
165+ await this . ioHelper . notify ( IO . CDK_TOOLKIT_E5035 . msg ( 'Error occurred while monitoring logs: %s' , { error : e } ) ) ;
140166 }
141167
142- this . scheduleNextTick ( SLEEP ) ;
168+ this . scheduleNextTick ( ) ;
143169 }
144170
145171 /**
@@ -161,15 +187,16 @@ export class CloudWatchLogEventMonitor {
161187 /**
162188 * Print out a cloudwatch event
163189 */
164- private print ( event : CloudWatchLogEvent ) : void {
165- info (
190+ private async print ( event : CloudWatchLogEvent ) : Promise < void > {
191+ await this . ioHelper . notify ( IO . CDK_TOOLKIT_I5033 . msg (
166192 util . format (
167193 '[%s] %s %s' ,
168194 chalk . blue ( event . logGroupName ) ,
169195 chalk . yellow ( event . timestamp . toLocaleTimeString ( ) ) ,
170196 event . message . trim ( ) ,
171197 ) ,
172- ) ;
198+ event ,
199+ ) ) ;
173200 }
174201
175202 /**
0 commit comments