1
- import EventEmitter from 'events'
2
-
3
- import bfj from 'bfj'
4
- import figures from 'figures'
5
1
import format from 'date-fns/format'
6
2
import parseISO from 'date-fns/parseISO'
7
-
3
+ import figures from 'figures'
4
+ import EventEmitter from 'node:events'
5
+ import { createWriteStream } from 'node:fs'
6
+ import { Readable , Transform } from 'node:stream'
7
+ import { pipeline } from 'node:stream/promises'
8
8
import getEntityName from './get-entity-name'
9
9
10
10
export const logEmitter = new EventEmitter ( )
@@ -47,7 +47,9 @@ export function formatLogMessageOneLine (logMessage) {
47
47
errorOutput . push ( `Entity: ${ getEntityName ( data . entity ) } ` )
48
48
}
49
49
if ( 'details' in data && 'errors' in data . details ) {
50
- const errorList = data . details . errors . map ( ( error ) => error . details || error . name )
50
+ const errorList = data . details . errors . map (
51
+ ( error ) => error . details || error . name
52
+ )
51
53
errorOutput . push ( `Details: ${ errorList . join ( ', ' ) } ` )
52
54
}
53
55
if ( 'requestId' in data ) {
@@ -78,7 +80,9 @@ export function formatLogMessageLogfile (logMessage) {
78
80
} catch ( err ) {
79
81
// Fallback for errors without API information
80
82
if ( logMessage . error . stack ) {
81
- logMessage . error . stacktrace = logMessage . error . stack . toString ( ) . split ( / \n + a t / )
83
+ logMessage . error . stacktrace = logMessage . error . stack
84
+ . toString ( )
85
+ . split ( / \n + a t / )
82
86
}
83
87
}
84
88
@@ -94,47 +98,78 @@ export function formatLogMessageLogfile (logMessage) {
94
98
// Display all errors
95
99
export function displayErrorLog ( errorLog ) {
96
100
if ( errorLog . length ) {
97
- const count = errorLog . reduce ( ( count , curr ) => {
98
- if ( Object . prototype . hasOwnProperty . call ( curr , 'warning' ) ) count . warnings ++
99
- else if ( Object . prototype . hasOwnProperty . call ( curr , 'error' ) ) count . errors ++
100
- return count
101
- } , { warnings : 0 , errors : 0 } )
102
-
103
- console . log ( `\n\nThe following ${ count . errors } errors and ${ count . warnings } warnings occurred:\n` )
101
+ const count = errorLog . reduce (
102
+ ( count , curr ) => {
103
+ if ( Object . prototype . hasOwnProperty . call ( curr , 'warning' ) ) {
104
+ count . warnings ++
105
+ } else if ( Object . prototype . hasOwnProperty . call ( curr , 'error' ) ) {
106
+ count . errors ++
107
+ }
108
+ return count
109
+ } ,
110
+ { warnings : 0 , errors : 0 }
111
+ )
112
+
113
+ console . log (
114
+ `\n\nThe following ${ count . errors } errors and ${ count . warnings } warnings occurred:\n`
115
+ )
104
116
105
117
errorLog
106
- . map ( ( logMessage ) => `${ format ( parseISO ( logMessage . ts ) , 'HH:mm:ss' ) } - ${ formatLogMessageOneLine ( logMessage ) } ` )
118
+ . map (
119
+ ( logMessage ) =>
120
+ `${ format (
121
+ parseISO ( logMessage . ts ) ,
122
+ 'HH:mm:ss'
123
+ ) } - ${ formatLogMessageOneLine ( logMessage ) } `
124
+ )
107
125
. map ( ( logMessage ) => console . log ( logMessage ) )
108
126
109
127
return
110
128
}
111
129
console . log ( 'No errors or warnings occurred' )
112
130
}
113
131
114
- // Write all log messages instead of infos to the error log file
115
- export function writeErrorLogFile ( destination , errorLog ) {
116
- const logFileData = errorLog
117
- . map ( formatLogMessageLogfile )
118
-
119
- return bfj . write ( destination , logFileData , {
120
- circular : 'ignore' ,
121
- space : 2
132
+ /**
133
+ * Write all log messages instead of infos to the error log file
134
+ * @param {import('node:fs').PathLike } destination
135
+ * @param {Record<string, unknown>[] } errorLog
136
+ * @returns {Promise<void> }
137
+ */
138
+ export async function writeErrorLogFile ( destination , errorLog ) {
139
+ const formatLogTransformer = new Transform ( {
140
+ objectMode : true ,
141
+ transform : ( chunk , encoding , callback ) => {
142
+ const formattedChunk = formatLogMessageLogfile ( chunk )
143
+ callback ( null , Buffer . from ( JSON . stringify ( formattedChunk ) ) )
144
+ }
122
145
} )
123
- . then ( ( ) => {
124
- console . log ( '\nStored the detailed error log file at:' )
125
- console . log ( destination )
126
- } )
127
- . catch ( ( e ) => {
128
- // avoid crashing when writing the log file fails
129
- console . error ( e )
130
- } )
146
+
147
+ const logFileWriteStream = createWriteStream ( destination )
148
+
149
+ try {
150
+ await pipeline ( [
151
+ Readable . from ( errorLog ) ,
152
+ formatLogTransformer ,
153
+ logFileWriteStream
154
+ ] )
155
+
156
+ console . log ( '\nStored the detailed error log file at:' )
157
+ console . log ( destination )
158
+ } catch ( err ) {
159
+ // avoid crashing when writing the log file fails
160
+ console . error ( err )
161
+ }
131
162
}
132
163
133
- // Init listeners for log messages, transform them into proper format and logs/displays them
164
+ /**
165
+ * Init listeners for log messages, transform them into proper format and logs/displays them
166
+ * @param {Record<string,unknown>[] } log
167
+ * @returns {Promise<void> }
168
+ */
134
169
export function setupLogging ( log ) {
135
170
function errorLogger ( level , error ) {
136
171
const logMessage = {
137
- ts : ( new Date ( ) ) . toJSON ( ) ,
172
+ ts : new Date ( ) . toJSON ( ) ,
138
173
level,
139
174
[ level ] : error
140
175
}
@@ -149,7 +184,11 @@ export function setupLogging (log) {
149
184
logEmitter . addListener ( 'error' , ( error ) => errorLogger ( 'error' , error ) )
150
185
}
151
186
152
- // Format log message to display them as task status
187
+ /**
188
+ * Format log message to display them as task status
189
+ * @template {Ctx}
190
+ * @param {import('listr').ListrTaskWrapper<Ctx> } task
191
+ */
153
192
export function logToTaskOutput ( task ) {
154
193
function logToTask ( logMessage ) {
155
194
const content = formatLogMessageOneLine ( logMessage )
0 commit comments