Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: pass logger to integrations #7816

Merged
merged 2 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
23 changes: 23 additions & 0 deletions .changeset/odd-books-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
'astro': minor
---

Integrations can now log messages using Astro’s built-in logger.

The logger is available to all hooks as an additional parameter:

```ts
import {AstroIntegration} from "./astro";

// integration.js
export function myIntegration(): AstroIntegration {
return {
name: "my-integration",
hooks: {
"astro:config:done": ({ logger }) => {
logger.info("Configure integration...");
}
}
}
}
```
25 changes: 20 additions & 5 deletions packages/astro/src/@types/astro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type { AstroCookies } from '../core/cookies';
import type { LogOptions } from '../core/logger/core';
import type { AstroComponentFactory, AstroComponentInstance } from '../runtime/server';
import type { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from './../core/constants.js';
import { AstroIntegrationLogger } from '../core/logger/core';
export type {
MarkdownHeading,
MarkdownMetadata,
Expand Down Expand Up @@ -1866,6 +1867,7 @@ export interface AstroIntegration {
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: (injectRoute: InjectedRoute) => void;
addClientDirective: (directive: ClientDirectiveConfig) => void;
logger: AstroIntegrationLogger;
// TODO: Add support for `injectElement()` for full HTML element injection, not just scripts.
// This may require some refactoring of `scripts`, `styles`, and `links` into something
// more generalized. Consider the SSR use-case as well.
Expand All @@ -1874,10 +1876,17 @@ export interface AstroIntegration {
'astro:config:done'?: (options: {
config: AstroConfig;
setAdapter: (adapter: AstroAdapter) => void;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:server:setup'?: (options: { server: vite.ViteDevServer }) => void | Promise<void>;
'astro:server:start'?: (options: { address: AddressInfo }) => void | Promise<void>;
'astro:server:done'?: () => void | Promise<void>;
'astro:server:setup'?: (options: {
server: vite.ViteDevServer;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:server:start'?: (options: {
address: AddressInfo;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:server:done'?: (options: { logger: AstroIntegrationLogger }) => void | Promise<void>;
'astro:build:ssr'?: (options: {
manifest: SerializedSSRManifest;
/**
Expand All @@ -1889,19 +1898,25 @@ export interface AstroIntegration {
* File path of the emitted middleware
*/
middlewareEntryPoint: URL | undefined;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:build:start'?: () => void | Promise<void>;
'astro:build:start'?: (options: { logger: AstroIntegrationLogger }) => void | Promise<void>;
'astro:build:setup'?: (options: {
vite: vite.InlineConfig;
pages: Map<string, PageBuildData>;
target: 'client' | 'server';
updateConfig: (newConfig: vite.InlineConfig) => void;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:build:generated'?: (options: {
dir: URL;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
'astro:build:generated'?: (options: { dir: URL }) => void | Promise<void>;
'astro:build:done'?: (options: {
pages: { pathname: string }[];
dir: URL;
routes: RouteData[];
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
};
}
Expand Down
2 changes: 1 addition & 1 deletion packages/astro/src/core/logger/console.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const consoleLogDestination = {

function getPrefix() {
let prefix = '';
let type = event.type;
let type = event.label;
if (type) {
// hide timestamp when type is undefined
prefix += dim(dateTimeFormat.format(new Date()) + ' ');
Expand Down
69 changes: 59 additions & 10 deletions packages/astro/src/core/logger/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ interface LogWritable<T> {
}

export type LoggerLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'; // same as Pino
export type LoggerEvent = 'info' | 'warn' | 'error';

export interface LogOptions {
dest: LogWritable<LogMessage>;
Expand All @@ -29,7 +28,7 @@ export const dateTimeFormat = new Intl.DateTimeFormat([], {
});

export interface LogMessage {
type: string | null;
label: string | null;
level: LoggerLevel;
message: string;
}
Expand All @@ -43,11 +42,11 @@ export const levels: Record<LoggerLevel, number> = {
};

/** Full logging API */
export function log(opts: LogOptions, level: LoggerLevel, type: string | null, message: string) {
export function log(opts: LogOptions, level: LoggerLevel, label: string | null, message: string) {
const logLevel = opts.level;
const dest = opts.dest;
const event: LogMessage = {
type,
label,
level,
message,
};
Expand All @@ -61,18 +60,18 @@ export function log(opts: LogOptions, level: LoggerLevel, type: string | null, m
}

/** Emit a user-facing message. Useful for UI and other console messages. */
export function info(opts: LogOptions, type: string | null, message: string) {
return log(opts, 'info', type, message);
export function info(opts: LogOptions, label: string | null, message: string) {
return log(opts, 'info', label, message);
}

/** Emit a warning message. Useful for high-priority messages that aren't necessarily errors. */
export function warn(opts: LogOptions, type: string | null, message: string) {
return log(opts, 'warn', type, message);
export function warn(opts: LogOptions, label: string | null, message: string) {
return log(opts, 'warn', label, message);
}

/** Emit a error message, Useful when Astro can't recover from some error. */
export function error(opts: LogOptions, type: string | null, message: string) {
return log(opts, 'error', type, message);
export function error(opts: LogOptions, label: string | null, message: string) {
return log(opts, 'error', label, message);
}

type LogFn = typeof info | typeof warn | typeof error;
Expand Down Expand Up @@ -127,3 +126,53 @@ export function timerMessage(message: string, startTime: number = Date.now()) {
timeDiff < 750 ? `${Math.round(timeDiff)}ms` : `${(timeDiff / 1000).toFixed(1)}s`;
return `${message} ${dim(timeDisplay)}`;
}

export class Logger {
options: LogOptions;
constructor(options: LogOptions) {
this.options = options;
}

info(label: string, message: string) {
info(this.options, label, message);
}
warn(label: string, message: string) {
warn(this.options, label, message);
}
error(label: string, message: string) {
error(this.options, label, message);
}
debug(label: string, message: string) {
debug(this.options, label, message);
}
}

export class AstroIntegrationLogger {
options: LogOptions;
label: string;

constructor(logging: LogOptions, label: string) {
this.options = logging;
this.label = label;
}

/**
* Creates a new logger instance with a new label, but the same log options.
*/
fork(label: string): AstroIntegrationLogger {
return new AstroIntegrationLogger(this.options, label);
}

info(message: string) {
info(this.options, this.label, message);
}
warn(message: string) {
warn(this.options, this.label, message);
}
error(message: string) {
error(this.options, this.label, message);
}
debug(message: string) {
debug(this.options, this.label, message);
}
}
14 changes: 7 additions & 7 deletions packages/astro/src/core/logger/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ export const nodeLogDestination = new Writable({

function getPrefix() {
let prefix = '';
let type = event.type;
if (type) {
let label = event.label;
if (label) {
// hide timestamp when type is undefined
prefix += dim(dateTimeFormat.format(new Date()) + ' ');
if (event.level === 'info') {
type = bold(cyan(`[${type}]`));
label = bold(cyan(`[${label}]`));
} else if (event.level === 'warn') {
type = bold(yellow(`[${type}]`));
label = bold(yellow(`[${label}]`));
} else if (event.level === 'error') {
type = bold(red(`[${type}]`));
label = bold(red(`[${label}]`));
}

prefix += `${type} `;
prefix += `${label} `;
}
return reset(prefix);
}
Expand Down Expand Up @@ -87,7 +87,7 @@ export const nodeLogOptions: Required<LogOptions> = {
};

export interface LogMessage {
type: string | null;
label: string | null;
level: LoggerLevel;
message: string;
}
Expand Down
Loading