Problem
`adapt-migrations` uses its own `Logger` singleton (`Logger.getInstance()`) which writes `info`/`debug`/`warn` directly to `console`. The AT's `logLevels` config has no effect on it.
In a typical run there are hundreds of lines per migrated combo:
```
(date) -- info -- Describe -- ... -- Registered
(date) -- info -- whereFromPlugin -- ... -- (stopped/success)
(date) -- info -- whereContent -- ... -- (success)
(date) -- info -- mutateContent -- ... -- (success)
(date) -- info -- checkContent -- ... -- (success)
(date) -- info -- updatePlugin -- ... -- (success)
```
This makes the AT's own logs (and any `console.log` debugging) practically unreadable during imports/updates. It's also unhelpful: the migration trace is rarely useful unless something goes wrong, and it's gone by the time you'd want to inspect it.
Why a custom `logger` arg won't fix it
Some sites in adapt-migrations (`Task.runApplicable`, `Task.run`, `Task.load`) accept a `logger` argument. But a number of others — `api/describe.js`, `api/tests.js`, `api/errors.js`, `lib/lifecycle.js` — call `Logger.getInstance()` directly. Replacing the singleton's methods is the only way to capture every call site.
Proposed fix
Add an optional config to this module: `migrationLogFile` (string path).
- Unset (default): existing behaviour (logs to stdout). Backwards-compatible.
- Set: in `AdaptFrameworkModule.init()`, monkey-patch `Logger.getInstance().info` / `.debug` / `.warn` to append to the configured file with a timestamp prefix.
- Leave `logger.error` on stdout (and also write to file), so genuine failures aren't hidden.
Sketch:
```js
const logFile = this.getConfig('migrationLogFile')
if (logFile) {
const { Logger } = await import('adapt-migrations')
const logger = Logger.getInstance()
const stream = fs.createWriteStream(logFile, { flags: 'a' })
const route = (level) => (...args) =>
stream.write(`[${new Date().toISOString()}] ${level} ${args.map(String).join(' ')}\n`)
logger.info = route('info')
logger.debug = route('debug')
logger.warn = route('warn')
}
```
Schema entry:
```json
"migrationLogFile": {
"description": "When set, info/debug/warn output from migrations is appended to the given file instead of stdout. Errors still surface to stdout.",
"type": "string"
}
```
Notes
- Could also live upstream in `adapt-migrations` itself (e.g. `Logger.setLevel()` or `Logger.setOutput()`) — that'd benefit every consumer of the library — but the AT-side patch is much cheaper to land and self-contained.
- Reduces the appeal of the bigger ask of "respect AT log levels", which would require a larger refactor.
Problem
`adapt-migrations` uses its own `Logger` singleton (`Logger.getInstance()`) which writes `info`/`debug`/`warn` directly to `console`. The AT's `logLevels` config has no effect on it.
In a typical run there are hundreds of lines per migrated combo:
```
(date) -- info -- Describe -- ... -- Registered
(date) -- info -- whereFromPlugin -- ... -- (stopped/success)
(date) -- info -- whereContent -- ... -- (success)
(date) -- info -- mutateContent -- ... -- (success)
(date) -- info -- checkContent -- ... -- (success)
(date) -- info -- updatePlugin -- ... -- (success)
```
This makes the AT's own logs (and any `console.log` debugging) practically unreadable during imports/updates. It's also unhelpful: the migration trace is rarely useful unless something goes wrong, and it's gone by the time you'd want to inspect it.
Why a custom `logger` arg won't fix it
Some sites in adapt-migrations (`Task.runApplicable`, `Task.run`, `Task.load`) accept a `logger` argument. But a number of others — `api/describe.js`, `api/tests.js`, `api/errors.js`, `lib/lifecycle.js` — call `Logger.getInstance()` directly. Replacing the singleton's methods is the only way to capture every call site.
Proposed fix
Add an optional config to this module: `migrationLogFile` (string path).
Sketch:
```js
const logFile = this.getConfig('migrationLogFile')
if (logFile) {
const { Logger } = await import('adapt-migrations')
const logger = Logger.getInstance()
const stream = fs.createWriteStream(logFile, { flags: 'a' })
const route = (level) => (...args) =>
stream.write(`[${new Date().toISOString()}] ${level} ${args.map(String).join(' ')}\n`)
logger.info = route('info')
logger.debug = route('debug')
logger.warn = route('warn')
}
```
Schema entry:
```json
"migrationLogFile": {
"description": "When set, info/debug/warn output from migrations is appended to the given file instead of stdout. Errors still surface to stdout.",
"type": "string"
}
```
Notes