Skip to content

Commit 49f3730

Browse files
feat: support custom logger (#6698)
1 parent a98cd8e commit 49f3730

File tree

13 files changed

+100
-43
lines changed

13 files changed

+100
-43
lines changed

packages/build/src/core/main.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { trace, context } from '@opentelemetry/api'
33

44
import { handleBuildError } from '../error/handle.js'
55
import { reportError } from '../error/report.js'
6-
import { getSystemLogger } from '../log/logger.js'
7-
import type { BufferedLogs } from '../log/logger.js'
6+
import { getLogsOutput, getSystemLogger } from '../log/logger.js'
7+
import type { Logs } from '../log/logger.js'
88
import { logTimer, logBuildSuccess } from '../log/messages/core.js'
99
import { getGeneratedFunctions } from '../steps/return_values.js'
1010
import { trackBuildComplete } from '../telemetry/main.js'
@@ -27,7 +27,7 @@ const tracer = trace.getTracer('core')
2727
export async function buildSite(flags: Partial<BuildFlags> = {}): Promise<{
2828
success: boolean
2929
severityCode: number
30-
logs: BufferedLogs | undefined
30+
logs: Logs | undefined
3131
netlifyConfig?: any
3232
configMutations?: any
3333
}> {
@@ -123,7 +123,7 @@ export async function buildSite(flags: Partial<BuildFlags> = {}): Promise<{
123123
success,
124124
severityCode,
125125
netlifyConfig: netlifyConfigA,
126-
logs,
126+
logs: getLogsOutput(logs),
127127
configMutations,
128128
generatedFunctions: getGeneratedFunctions(returnValues),
129129
}

packages/build/src/core/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ export type BuildCLIFlags = {
4444
export type BuildFlags = BuildCLIFlags & {
4545
env?: Record<string, unknown>
4646
eventHandlers?: EventHandlers
47+
/** Custom logger function to capture build output */
48+
logger?: (message: string) => void
4749
}
4850

4951
type EventHandlers = {

packages/build/src/error/monitor/start.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import Bugsnag from '@bugsnag/js'
44
import memoizeOne from 'memoize-one'
55

66
import type { ResolvedFlags } from '../../core/normalize_flags.js'
7-
import { BufferedLogs, log } from '../../log/logger.js'
7+
import { Logs, log } from '../../log/logger.js'
88
import { ROOT_PACKAGE_JSON } from '../../utils/json.js'
99

1010
const projectRoot = fileURLToPath(new URL('../../..', import.meta.url))
1111

1212
// Start a client to monitor errors
13-
export const startErrorMonitor = function (config: { flags: ResolvedFlags; logs?: BufferedLogs; bugsnagKey?: string }) {
13+
export const startErrorMonitor = function (config: { flags: ResolvedFlags; logs?: Logs; bugsnagKey?: string }) {
1414
const {
1515
flags: { mode },
1616
logs,

packages/build/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { buildSite } from './core/main.js'
22
export { NetlifyPluginConstants } from './core/constants.js'
33

4+
export type { LogOutput as Logs } from './log/logger.js'
45
export type { GeneratedFunction } from './steps/return_values.js'
56
// export the legacy types
67
export type { NetlifyPlugin } from './types/netlify_plugin.js'

packages/build/src/log/logger.ts

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { THEME } from './theme.js'
1212

1313
export type Logs = BufferedLogs | StreamedLogs
1414
export type BufferedLogs = { stdout: string[]; stderr: string[]; outputFlusher?: OutputFlusher }
15-
export type StreamedLogs = { outputFlusher?: OutputFlusher }
15+
export type StreamedLogs = { outputFlusher?: OutputFlusher; logFunction?: (message: string) => void }
1616

1717
export const logsAreBuffered = (logs: Logs | undefined): logs is BufferedLogs => {
1818
return logs !== undefined && 'stdout' in logs
@@ -31,13 +31,16 @@ const EMPTY_LINE = '\u{200B}'
3131
* When the `buffer` option is true, we return logs instead of printing them
3232
* on the console. The logs are accumulated in a `logs` array variable.
3333
*/
34-
export const getBufferLogs = (config: { buffer?: boolean }): BufferedLogs | undefined => {
35-
const { buffer = false } = config
36-
if (!buffer) {
37-
return
34+
export const getBufferLogs = (config: { buffer?: boolean; logger?: (message: string) => void }): Logs | undefined => {
35+
const { buffer = false, logger } = config
36+
37+
if (logger) {
38+
return { logFunction: logger }
3839
}
3940

40-
return { stdout: [], stderr: [] }
41+
if (buffer) {
42+
return { stdout: [], stderr: [] }
43+
}
4144
}
4245

4346
// Core logging utility, used by the other methods.
@@ -64,9 +67,28 @@ export const log = function (
6467
return
6568
}
6669

70+
if (typeof logs?.logFunction === 'function') {
71+
logs.logFunction(stringC)
72+
73+
return
74+
}
75+
6776
console.log(stringC)
6877
}
6978

79+
export type LogOutput = Pick<BufferedLogs, 'stderr' | 'stdout'>
80+
81+
// Returns a `logs` object to be returned in the public interface,
82+
// always containing a `stderr` and `stdout` arrays, regardless of
83+
// whether the `buffer` input property was used.
84+
export const getLogsOutput = (logs: Logs | undefined): LogOutput => {
85+
if (!logs || !logsAreBuffered(logs)) {
86+
return { stdout: [], stderr: [] }
87+
}
88+
89+
return { stdout: logs.stdout, stderr: logs.stderr }
90+
}
91+
7092
const serializeIndentedArray = function (array) {
7193
return serializeArray(array.map(serializeIndentedItem))
7294
}
@@ -75,61 +97,61 @@ const serializeIndentedItem = function (item) {
7597
return indentString(item, INDENT_SIZE + 1).trimStart()
7698
}
7799

78-
export const logError = function (logs: BufferedLogs | undefined, string: string, opts = {}) {
100+
export const logError = function (logs: Logs | undefined, string: string, opts = {}) {
79101
log(logs, string, { color: THEME.errorLine, ...opts })
80102
}
81103

82-
export const logWarning = function (logs: BufferedLogs | undefined, string: string, opts = {}) {
104+
export const logWarning = function (logs: Logs | undefined, string: string, opts = {}) {
83105
log(logs, string, { color: THEME.warningLine, ...opts })
84106
}
85107

86108
// Print a message that is under a header/subheader, i.e. indented
87-
export const logMessage = function (logs: BufferedLogs | undefined, string: string, opts = {}) {
109+
export const logMessage = function (logs: Logs | undefined, string: string, opts = {}) {
88110
log(logs, string, { indent: true, ...opts })
89111
}
90112

91113
// Print an object
92-
export const logObject = function (logs: BufferedLogs | undefined, object, opts) {
114+
export const logObject = function (logs: Logs | undefined, object, opts) {
93115
logMessage(logs, serializeObject(object), opts)
94116
}
95117

96118
// Print an array
97-
export const logArray = function (logs: BufferedLogs | undefined, array, opts = {}) {
119+
export const logArray = function (logs: Logs | undefined, array, opts = {}) {
98120
logMessage(logs, serializeIndentedArray(array), { color: THEME.none, ...opts })
99121
}
100122

101123
// Print an array of errors
102-
export const logErrorArray = function (logs: BufferedLogs | undefined, array, opts = {}) {
124+
export const logErrorArray = function (logs: Logs | undefined, array, opts = {}) {
103125
logMessage(logs, serializeIndentedArray(array), { color: THEME.errorLine, ...opts })
104126
}
105127

106128
// Print an array of warnings
107-
export const logWarningArray = function (logs: BufferedLogs | undefined, array, opts = {}) {
129+
export const logWarningArray = function (logs: Logs | undefined, array, opts = {}) {
108130
logMessage(logs, serializeIndentedArray(array), { color: THEME.warningLine, ...opts })
109131
}
110132

111133
// Print a main section header
112-
export const logHeader = function (logs: BufferedLogs | undefined, string: string, opts = {}) {
134+
export const logHeader = function (logs: Logs | undefined, string: string, opts = {}) {
113135
log(logs, `\n${getHeader(string)}`, { color: THEME.header, ...opts })
114136
}
115137

116138
// Print a main section header, when an error happened
117-
export const logErrorHeader = function (logs: BufferedLogs | undefined, string: string, opts = {}) {
139+
export const logErrorHeader = function (logs: Logs | undefined, string: string, opts = {}) {
118140
logHeader(logs, string, { color: THEME.errorHeader, ...opts })
119141
}
120142

121143
// Print a sub-section header
122-
export const logSubHeader = function (logs: BufferedLogs | undefined, string: string, opts = {}) {
144+
export const logSubHeader = function (logs: Logs | undefined, string: string, opts = {}) {
123145
log(logs, `\n${figures.pointer} ${string}`, { color: THEME.subHeader, ...opts })
124146
}
125147

126148
// Print a sub-section header, when an error happened
127-
export const logErrorSubHeader = function (logs: BufferedLogs | undefined, string: string, opts = {}) {
149+
export const logErrorSubHeader = function (logs: Logs | undefined, string: string, opts = {}) {
128150
logSubHeader(logs, string, { color: THEME.errorSubHeader, ...opts })
129151
}
130152

131153
// Print a sub-section header, when a warning happened
132-
export const logWarningSubHeader = function (logs: BufferedLogs | undefined, string: string, opts = {}) {
154+
export const logWarningSubHeader = function (logs: Logs | undefined, string: string, opts = {}) {
133155
logSubHeader(logs, string, { color: THEME.warningSubHeader, ...opts })
134156
}
135157

@@ -162,7 +184,7 @@ export const reduceLogLines = function (lines) {
162184
* the user-facing build logs)
163185
*/
164186
export const getSystemLogger = function (
165-
logs: BufferedLogs | undefined,
187+
logs: Logs | undefined,
166188
debug: boolean,
167189
/** A system log file descriptor, if non is provided it will be a noop logger */
168190
systemLogFile?: number,
@@ -192,15 +214,7 @@ export const getSystemLogger = function (
192214
return (...args) => fileDescriptor.write(`${reduceLogLines(args)}\n`)
193215
}
194216

195-
export const addOutputFlusher = (logs: Logs, outputFlusher: OutputFlusher): Logs => {
196-
if (logsAreBuffered(logs)) {
197-
return {
198-
...logs,
199-
outputFlusher,
200-
}
201-
}
202-
203-
return {
204-
outputFlusher,
205-
}
206-
}
217+
export const addOutputFlusher = (logs: Logs, outputFlusher: OutputFlusher): Logs => ({
218+
...logs,
219+
outputFlusher,
220+
})

packages/build/src/log/messages/config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@ const INTERNAL_FLAGS = [
5959
'enhancedSecretScan',
6060
'edgeFunctionsBootstrapURL',
6161
'eventHandlers',
62+
'logger',
6263
]
6364
const HIDDEN_FLAGS = [...SECURE_FLAGS, ...TEST_FLAGS, ...INTERNAL_FLAGS]
64-
const HIDDEN_DEBUG_FLAGS = [...SECURE_FLAGS, ...TEST_FLAGS, 'eventHandlers']
65+
const HIDDEN_DEBUG_FLAGS = [...SECURE_FLAGS, ...TEST_FLAGS, 'eventHandlers', 'logger']
6566

6667
export const logBuildDir = function (logs, buildDir) {
6768
logSubHeader(logs, 'Current directory')

packages/build/src/log/messages/core.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import { serializeLogError } from '../../error/parse/serialize_log.js'
66
import { roundTimerToMillisecs } from '../../time/measure.js'
77
import { ROOT_PACKAGE_JSON } from '../../utils/json.js'
88
import { getLogHeaderFunc } from '../header_func.js'
9-
import { log, logMessage, logWarning, logHeader, logSubHeader, logWarningArray, BufferedLogs } from '../logger.js'
9+
import { log, logMessage, logWarning, logHeader, logSubHeader, logWarningArray, Logs } from '../logger.js'
1010
import { OutputFlusher } from '../output_flusher.js'
1111
import { THEME } from '../theme.js'
1212

1313
import { logConfigOnError } from './config.js'
1414

15-
export const logBuildStart = function (logs?: BufferedLogs) {
15+
export const logBuildStart = function (logs?: Logs) {
1616
logHeader(logs, 'Netlify Build')
1717
logSubHeader(logs, 'Version')
1818
logMessage(logs, `${ROOT_PACKAGE_JSON.name} ${ROOT_PACKAGE_JSON.version}`)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
name: test
2+
inputs: []
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[[plugins]]
2+
package = "./plugin"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default async () => new Response("Hello")
2+
3+
export const config = {
4+
path: "/hello"
5+
}

0 commit comments

Comments
 (0)