Skip to content

Commit

Permalink
feat(runtime-logger): Expose integration logger on runtime (#125)
Browse files Browse the repository at this point in the history
Co-authored-by: Adam Matthiesen <30383579+Adammatthiesen@users.noreply.github.com>
Co-authored-by: Florian Lefebvre <69633530+florian-lefebvre@users.noreply.github.com>
  • Loading branch information
3 people committed Jul 8, 2024
1 parent fe6f703 commit 30bb61a
Show file tree
Hide file tree
Showing 23 changed files with 517 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/wild-boxes-judge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@inox-tools/runtime-logger': minor
---

Expose `AstroIntegrationLogger` in runtime
3 changes: 3 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ pkg/aik-route-config:
pkg/custom-routing:
- 'packages/custom-routing/**'

pkg/runtime-logger:
- 'packages/runtime-logger/**'

pkg/inline-mod:
- 'packages/inline-mod/**'

Expand Down
4 changes: 4 additions & 0 deletions docs/astro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export default defineConfig({
label: 'Astro When',
link: '/astro-when',
},
{
label: 'Runtime Logger',
link: '/runtime-logger',
},
],
},
{
Expand Down
3 changes: 2 additions & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"@vercel/analytics": "^1.3.1",
"astro": "^4.11.5",
"sharp": "^0.33.4",
"starlight-links-validator": "^0.9.1"
"starlight-links-validator": "^0.9.1",
"starlight-package-managers": "^0.6.0"
},
"devDependencies": {
"@astrojs/check": "^0.7.0",
Expand Down
48 changes: 48 additions & 0 deletions docs/src/content/docs/runtime-logger.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: Runtime Logger
packageName: '@inox-tools/runtime-logger'
description: Access your Astro Integration Logger from the runtime of your integration.
---

Astro provides [a logger (typed `AstroIntegrationLogger`)](https://docs.astro.build/en/reference/integrations-reference/#astrointegrationlogger) configured for each integration on all the official [integration hooks](https://docs.astro.build/en/reference/integrations-reference/#hooks). But this logger is only accessible on the code configuring the integration, not for any runtime modules defined by it.

This integration allows you to access the logger from the runtime of your integration.

## Installing the integration

import { PackageManagers } from 'starlight-package-managers';

<PackageManagers pkg="@inox-tools/runtime-logger" />

## Using the integration

To enable this, you need to register your integration to have a runtime logger under some name:

```ts title="your-integration/index.ts" ins={1,7-9}
import { runtimeLogger } from '@inox-tools/runtime-logger';

export default () => ({
name: 'your-integration',
hooks: {
'astro:config:setup': (params) => {
runtimeLogger(params, {
name: 'your-integration',
});
},
},
});
```

With that in place, your runtime code can now access the logger by importing the generated module `@it-astro:logger:<name>`:

```astro title="injected-route.astro"
---
import { logger } from '@it-astro:logger:your-integration';
logger.info('Hello World!');
---
```

## License

Astro Runtime Logger is available under the MIT license.
4 changes: 4 additions & 0 deletions examples/content-injection/integration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { injectCollections } from '@inox-tools/content-utils';
import { runtimeLogger } from '@inox-tools/runtime-logger';
import { defineIntegration } from 'astro-integration-kit';

export default defineIntegration({
Expand All @@ -7,6 +8,9 @@ export default defineIntegration({
return {
hooks: {
'astro:config:setup': (params) => {
runtimeLogger(params, {
name: 'test-integration',
});
injectCollections(params, {
entrypoint: './src/integration/config.ts',
seedTemplateDirectory: './src/integration',
Expand Down
1 change: 1 addition & 0 deletions examples/content-injection/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"dependencies": {
"@astrojs/check": "^0.7.0",
"@inox-tools/content-utils": "workspace:^",
"@inox-tools/runtime-logger": "workspace:^",
"astro": "^4.11.5",
"astro-integration-kit": "^0.14.0",
"typescript": "^5.5.3"
Expand Down
3 changes: 3 additions & 0 deletions examples/content-injection/src/pages/index.astro
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
---
import { getLatestCommitDate, getOldestCommitDate } from '@it-astro:content/git';
import { getCollection } from 'astro:content';
import { logger } from '@it-astro:logger:test-integration';
const entries = await getCollection('blog');
logger.info(`Retrieved ${entries.length} entries`);
const dates = await Promise.all(
entries.map(async (entry) => {
const latest = await getLatestCommitDate(entry);
Expand Down
46 changes: 46 additions & 0 deletions packages/runtime-logger/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<p align="center">
<img alt="InoxTools" width="350px" src="https://github.com/Fryuni/inox-tools/blob/main/assets/shield.png?raw=true"/>
</p>

# Runtime Logger

Expose Astro Integration Logger at runtime for consistent output

## Install

```js
npm i @inox-tools/runtime-logger
```

## Using the integration

To enable this, you need to register your integration to have a runtime logger under some name:

```ts
import { runtimeLogger } from '@inox-tools/runtime-logger';

export default () => ({
name: 'your-integration',
hooks: {
'astro:config:setup': (params) => {
runtimeLogger(params, {
name: 'your-integration',
});
},
},
});
```

With that in place, your runtime code can now access the logger by importing the generated module `@it-astro:logger:<name>`:

```astro
---
import { logger } from '@it-astro:logger:your-integration';
logger.info('Hello World!');
---
```

## License

Astro Runtime Logger is available under the MIT license.
3 changes: 3 additions & 0 deletions packages/runtime-logger/npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
*.log
src
50 changes: 50 additions & 0 deletions packages/runtime-logger/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "@inox-tools/runtime-logger",
"version": "0.0.0",
"description": "Expose Astro Integration Logger at runtime for consistent output",
"keywords": [
"astro-integration",
"withastro",
"astro"
],
"license": "MIT",
"author": "Luiz Ferraz <luiz@lferraz.com>",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"files": [
"dist",
"src",
"template",
"virtual.d.ts"
],
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"prepublish": "pnpm run build",
"test": "echo 'No tests'"
},
"dependencies": {
"astro-integration-kit": "^0.14",
"@inox-tools/utils": "workspace:^",
"@inox-tools/modular-station": "workspace:^"
},
"devDependencies": {
"@types/node": "^20",
"@vitest/coverage-v8": "^1",
"@vitest/ui": "^1",
"jest-extended": "^4",
"astro": "^4",
"tsup": "^8",
"typescript": "^5",
"vite": "^5",
"vitest": "^1"
},
"peerDependencies": {
"astro": "^4"
}
}
45 changes: 45 additions & 0 deletions packages/runtime-logger/src/buildLoggerPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { Plugin } from 'vite';
import type { AstroIntegrationLogger } from 'astro';
import { INTERNAL_MODULE } from './internalPlugin.js';

const MODULE_PREFIX = '@it-astro:logger:';
const RESOLVED_MODULE_PREFIX = '\x00@it-astro:logger:';

const pluginName = '@inox-tools/runtime-logger/dev';

export const buildLoggerPlugin = (loggers: Map<string, AstroIntegrationLogger>): Plugin => {
(globalThis as any)[Symbol.for(pluginName)] = loggers;

return {
name: pluginName,
resolveId(id) {
if (id.startsWith(MODULE_PREFIX)) {
const loggerName = id.slice(MODULE_PREFIX.length);
if (loggers.has(loggerName)) {
return `${RESOLVED_MODULE_PREFIX}${loggerName}`;
}
}
return null;
},
load(id) {
if (!id.startsWith(RESOLVED_MODULE_PREFIX)) return;
const loggerName = id.slice(RESOLVED_MODULE_PREFIX.length);
const logger = loggers.get(loggerName)!;
if (logger === undefined) return;

return `
import { baseLogger } from ${JSON.stringify(INTERNAL_MODULE)};
const buildLogger = globalThis[Symbol.for(${JSON.stringify(pluginName)})]?.get(${JSON.stringify(loggerName)});
const logger = buildLogger ?? baseLogger.fork(${JSON.stringify(logger.label)});
if (buildLogger === undefined) {
logger.options.level = ${JSON.stringify(logger.options.level)};
}
export { logger };
`;
},
};
};
35 changes: 35 additions & 0 deletions packages/runtime-logger/src/devLoggerPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Plugin } from 'vite';
import type { AstroIntegrationLogger } from 'astro';

const MODULE_PREFIX = '@it-astro:logger:';
const RESOLVED_MODULE_PREFIX = '\x00@it-astro:logger:';

const pluginName = '@inox-tools/runtime-logger/dev';

export const devLoggerPlugin = (loggers: Map<string, AstroIntegrationLogger>): Plugin => {
(globalThis as any)[Symbol.for(pluginName)] = loggers;

return {
name: pluginName,
resolveId(id) {
if (id.startsWith(MODULE_PREFIX)) {
const loggerName = id.slice(MODULE_PREFIX.length);
if (loggers.has(loggerName)) {
return `${RESOLVED_MODULE_PREFIX}${loggerName}`;
}
}
return null;
},
load(id) {
if (!id.startsWith(RESOLVED_MODULE_PREFIX)) return;
const loggerName = id.slice(RESOLVED_MODULE_PREFIX.length);
if (!loggers.has(loggerName)) return;

return `
const logger = globalThis[Symbol.for(${JSON.stringify(pluginName)})].get(${JSON.stringify(loggerName)});
export { logger };
`;
},
};
};
55 changes: 55 additions & 0 deletions packages/runtime-logger/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { withApi } from '@inox-tools/modular-station';
import { addVitePlugin, defineUtility, type HookParameters } from 'astro-integration-kit';
import { z } from 'astro/zod';
import { buildLoggerPlugin } from './buildLoggerPlugin.js';
import { loggerInternalsPlugin } from './internalPlugin.js';
import { devLoggerPlugin } from './devLoggerPlugin.js';
import type { AstroIntegrationLogger } from 'astro';

const schema = z
.object({
name: z.string(),
})
.strict();

const integration = withApi(() => {
const loggers = new Map<string, AstroIntegrationLogger>();

return {
name: '@inox-tools/runtime-logger',
hooks: {
'astro:config:setup': (params) => {
switch (params.command) {
case 'build': {
addVitePlugin(params, {
plugin: loggerInternalsPlugin,
warnDuplicated: true,
});
addVitePlugin(params, {
plugin: buildLoggerPlugin(loggers),
warnDuplicated: true,
});
}
case 'dev': {
addVitePlugin(params, {
plugin: devLoggerPlugin(loggers),
warnDuplicated: true,
});
}
}
},
},
addLogger(name: string, logger: AstroIntegrationLogger) {
loggers.set(name, logger);
},
};
});

export const runtimeLogger = defineUtility('astro:config:setup')((
params: HookParameters<'astro:config:setup'>,
options: z.infer<typeof schema>
) => {
const api = integration.fromSetup(params);

api.addLogger(options.name, params.logger);
});
21 changes: 21 additions & 0 deletions packages/runtime-logger/src/internalPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Plugin } from 'vite';
import { readFile } from 'fs/promises';

export const INTERNAL_MODULE = '@it-astro:logger-internal';
const RESOLVED_INTERNAL_MODULE = '\x00@it-astro:logger-internal';

const templatePath = new URL('../template/loggerStub.mjs', import.meta.url);

export const loggerInternalsPlugin: Plugin = {
name: '@inox-tools/runtime-logger/internal',
resolveId(id) {
if (id === INTERNAL_MODULE) {
return RESOLVED_INTERNAL_MODULE;
}
},
load(id) {
if (id !== RESOLVED_INTERNAL_MODULE) return;

return readFile(templatePath, 'utf-8');
},
};
Loading

0 comments on commit 30bb61a

Please sign in to comment.