Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/fix-node-logger-startup-message.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@astrojs/node': patch
'astro': patch
---

Fixes the `experimental.logger` destination not being used for the "Server listening on..." startup message. The logger is now resolved before the server starts listening, and `adapterLogger` re-creates itself when the underlying logger changes so the startup message uses the correct destination.
5 changes: 3 additions & 2 deletions packages/astro/src/core/app/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,10 @@ export abstract class BaseApp<P extends Pipeline = AppPipeline> {
}

get adapterLogger(): AstroIntegrationLogger {
if (!this.#adapterLogger) {
const currentOptions = this.logger.options;
if (!this.#adapterLogger || this.#adapterLogger.options !== currentOptions) {
this.#adapterLogger = new AstroIntegrationLogger(
this.logger.options,
currentOptions,
this.manifest.adapterName,
);
}
Expand Down
17 changes: 17 additions & 0 deletions packages/astro/test/units/app/logger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ function createAppWithLogger(experimentalLogger?: LoggerHandlerConfig) {
}

describe('SSR Logger', () => {
it('adapterLogger re-creates itself after the pipeline logger is replaced', async () => {
const app = createAppWithLogger({ entrypoint: 'astro/logger/json' });

// Access adapterLogger before getLogger(), caches it with the default options
const beforeOptions = app.adapterLogger.options;

await app.pipeline.getLogger();

// After getLogger() replaces pipeline.logger, adapterLogger should re-create
const afterOptions = app.adapterLogger.options;
assert.notEqual(
beforeOptions,
afterOptions,
'adapterLogger should re-create when the pipeline logger is replaced',
);
});

it('resolves a custom logger destination from the manifest on first request', async () => {
const app = createAppWithLogger({ entrypoint: 'astro/logger/json' });

Expand Down
7 changes: 6 additions & 1 deletion packages/integrations/node/src/standalone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ export default function standalone(
const server = createServer(handler, host, port);
server.server.listen(port, host);
if (process.env.ASTRO_NODE_LOGGING !== 'disabled') {
logListeningOn(app.adapterLogger, server.server, host);
// Resolve the user-configured logger before logging the startup message.
// getLogger() resolves before the OS finishes binding the port (and emitting
// 'listening'), so logListeningOn's once('listening') handler is registered
// in time. standalone() stays synchronous so callers receive the server object
// immediately, as they did before.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Resolve the user-configured logger before logging the startup message.
// getLogger() resolves before the OS finishes binding the port (and emitting
// 'listening'), so logListeningOn's once('listening') handler is registered
// in time. standalone() stays synchronous so callers receive the server object
// immediately, as they did before.

app.pipeline.getLogger().then(() => logListeningOn(app.adapterLogger, server.server, host));
}
server.server.on('close', () => {
app.logger.close();
Expand Down
Loading