@@ -9,17 +9,44 @@ const chalk = require('chalk');
9
9
const moment = require ( 'moment' ) ;
10
10
const os = require ( 'os' ) ;
11
11
12
+ function getApiLogGroupName ( apiId , alias ) {
13
+ return `API-Gateway-Execution-Logs_${ apiId } /${ alias } ` ;
14
+ }
15
+
12
16
module . exports = {
17
+
13
18
logsValidate ( ) {
14
- // validate function exists in service
15
19
this . _lambdaName = this . _serverless . service . getFunction ( this . options . function ) . name ;
16
-
17
- this . _options . interval = this . _options . interval || 1000 ;
18
20
this . _options . logGroupName = this . _provider . naming . getLogGroupName ( this . _lambdaName ) ;
21
+ this . _options . interval = this . _options . interval || 1000 ;
19
22
20
23
return BbPromise . resolve ( ) ;
21
24
} ,
22
25
26
+ apiLogsValidate ( ) {
27
+ if ( this . options . function ) {
28
+ return BbPromise . reject ( new this . serverless . classes . Error ( '--function is not supported for API logs.' ) ) ;
29
+ }
30
+
31
+ // Retrieve APIG id
32
+ return this . aliasStacksDescribeResource ( 'ApiGatewayRestApi' )
33
+ . then ( resources => {
34
+ if ( _ . isEmpty ( resources . StackResources ) ) {
35
+ return BbPromise . reject ( new this . serverless . classes . Error ( 'service does not contain any API' ) ) ;
36
+ }
37
+
38
+ const apiResource = _ . first ( resources . StackResources ) ;
39
+ const apiId = apiResource . PhysicalResourceId ;
40
+ this . _apiLogsLogGroup = getApiLogGroupName ( apiId , this . _alias ) ;
41
+ this . _options . interval = this . _options . interval || 1000 ;
42
+
43
+ this . options . verbose && this . serverless . cli . log ( `API id: ${ apiId } ` ) ;
44
+ this . options . verbose && this . serverless . cli . log ( `Log group: ${ this . _apiLogsLogGroup } ` ) ;
45
+
46
+ return BbPromise . resolve ( ) ;
47
+ } ) ;
48
+ } ,
49
+
23
50
logsGetLogStreams ( ) {
24
51
const params = {
25
52
logGroupName : this . _options . logGroupName ,
@@ -57,16 +84,48 @@ module.exports = {
57
84
58
85
} ,
59
86
60
- logsShowLogs ( logStreamNames ) {
61
- if ( ! logStreamNames || ! logStreamNames . length ) {
62
- if ( this . options . tail ) {
63
- return setTimeout ( ( ( ) => this . logsGetLogStreams ( )
64
- . then ( nextLogStreamNames => this . logsShowLogs ( nextLogStreamNames ) ) ) ,
65
- this . options . interval ) ;
87
+ apiLogsGetLogStreams ( ) {
88
+ const params = {
89
+ logGroupName : this . _apiLogsLogGroup ,
90
+ descending : true ,
91
+ limit : 50 ,
92
+ orderBy : 'LastEventTime' ,
93
+ } ;
94
+
95
+ return this . provider . request (
96
+ 'CloudWatchLogs' ,
97
+ 'describeLogStreams' ,
98
+ params ,
99
+ this . options . stage ,
100
+ this . options . region
101
+ )
102
+ . then ( reply => {
103
+ if ( ! reply || _ . isEmpty ( reply . logStreams ) ) {
104
+ return BbPromise . reject ( new this . serverless . classes . Error ( 'No logs exist for the API' ) ) ;
66
105
}
67
- }
68
106
69
- const formatLambdaLogEvent = ( msgParam ) => {
107
+ return _ . map ( reply . logStreams , stream => stream . logStreamName ) ;
108
+ } ) ;
109
+
110
+ } ,
111
+
112
+ apiLogsShowLogs ( logStreamNames ) {
113
+ const formatApiLogEvent = event => {
114
+ const dateFormat = 'YYYY-MM-DD HH:mm:ss.SSS (Z)' ;
115
+ const timestamp = chalk . green ( moment ( event . timestamp ) . format ( dateFormat ) ) ;
116
+
117
+ const parsedMessage = / \( ( .* ?) \) .* / . exec ( event . message ) ;
118
+ const header = `${ timestamp } ${ chalk . yellow ( parsedMessage [ 1 ] ) } ${ os . EOL } ` ;
119
+ const message = chalk . gray ( _ . replace ( event . message , / \( .* ?\) / , '' ) ) ;
120
+ return `${ header } ${ message } ${ os . EOL } ` ;
121
+ } ;
122
+
123
+ return this . logsShowLogs ( logStreamNames , formatApiLogEvent , this . apiLogsGetLogStreams . bind ( this ) ) ;
124
+ } ,
125
+
126
+ functionLogsShowLogs ( logStreamNames ) {
127
+ const formatLambdaLogEvent = event => {
128
+ const msgParam = event . message ;
70
129
let msg = msgParam ;
71
130
const dateFormat = 'YYYY-MM-DD HH:mm:ss.SSS (Z)' ;
72
131
@@ -92,8 +151,20 @@ module.exports = {
92
151
return `${ time } \t${ chalk . yellow ( reqId ) } \t${ text } ` ;
93
152
} ;
94
153
154
+ return this . logsShowLogs ( logStreamNames , formatLambdaLogEvent , this . logsGetLogStreams . bind ( this ) ) ;
155
+ } ,
156
+
157
+ logsShowLogs ( logStreamNames , formatter , getLogStreams ) {
158
+ if ( ! logStreamNames || ! logStreamNames . length ) {
159
+ if ( this . options . tail ) {
160
+ return setTimeout ( ( ( ) => getLogStreams ( )
161
+ . then ( nextLogStreamNames => this . logsShowLogs ( nextLogStreamNames , formatter ) ) ) ,
162
+ this . options . interval ) ;
163
+ }
164
+ }
165
+
95
166
const params = {
96
- logGroupName : this . options . logGroupName ,
167
+ logGroupName : this . options . logGroupName || this . _apiLogsLogGroup ,
97
168
interleaved : true ,
98
169
logStreamNames,
99
170
startTime : this . options . startTime ,
@@ -122,7 +193,7 @@ module.exports = {
122
193
. then ( results => {
123
194
if ( results . events ) {
124
195
_ . forEach ( results . events , e => {
125
- process . stdout . write ( formatLambdaLogEvent ( e . message ) ) ;
196
+ process . stdout . write ( formatter ( e ) ) ;
126
197
} ) ;
127
198
}
128
199
@@ -137,8 +208,8 @@ module.exports = {
137
208
this . options . startTime = _ . last ( results . events ) . timestamp + 1 ;
138
209
}
139
210
140
- return setTimeout ( ( ( ) => this . logsGetLogStreams ( )
141
- . then ( nextLogStreamNames => this . logsShowLogs ( nextLogStreamNames ) ) ) ,
211
+ return setTimeout ( ( ( ) => getLogStreams ( )
212
+ . then ( nextLogStreamNames => this . logsShowLogs ( nextLogStreamNames , formatter ) ) ) ,
142
213
this . options . interval ) ;
143
214
}
144
215
0 commit comments