@beespoke/micro-server-logger-winston 0.0.0-stage → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +69 -2
- package/dist/Logger.d.ts +13 -0
- package/dist/PluginContext.d.ts +13 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +104 -0
- package/dist/plugin/index.d.ts +9 -0
- package/dist/plugin/index.js +22 -0
- package/package.json +36 -4
package/README.md
CHANGED
|
@@ -1,3 +1,70 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @beespoke/micro-server-logger-winston
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Winston logging and CLI table output, usable directly or as the application logger.
|
|
4
|
+
|
|
5
|
+
Supports Node 24+ and Bun 1.3.14+.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install @beespoke/micro-server @beespoke/micro-server-logger-winston
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Use `bun add` in place of `npm install` for Bun projects.
|
|
14
|
+
|
|
15
|
+
## Configure the plugin
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { defineConfig } from '@beespoke/micro-server';
|
|
19
|
+
|
|
20
|
+
export default defineConfig({
|
|
21
|
+
plugins: ['@beespoke/micro-server-logger-winston'],
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Log messages
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { Logger } from '@beespoke/micro-server-logger-winston';
|
|
29
|
+
|
|
30
|
+
Logger.info('Application ready');
|
|
31
|
+
Logger.warn('Retrying request', { attempt: 2 });
|
|
32
|
+
Logger.error(new Error('Example error'));
|
|
33
|
+
Logger.table([{ name: 'worker', status: 'ready' }]);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The root exports `Logger` as both a named and default export. Methods include `info`, `warn`, `error`, `debug`, and `table`. Plugin registration selects this facade as core's application logger and registers shutdown cleanup. An explicit `logger` in core configuration takes precedence. Only one plugin may provide the application logger.
|
|
37
|
+
|
|
38
|
+
No plugin options are required; if provided, the options object must be empty. Standalone logging lazily creates its Winston instance; finish with `await Logger.close()`. The current default log level is `info`, so debug messages are filtered by that configuration.
|
|
39
|
+
|
|
40
|
+
## Start the application
|
|
41
|
+
|
|
42
|
+
Save the configuration as `micro-server.config.ts` next to your application's `package.json`, then create `index.ts`:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { ApplicationServer } from '@beespoke/micro-server';
|
|
46
|
+
|
|
47
|
+
await ApplicationServer.bootstrap();
|
|
48
|
+
for (const signal of ['SIGINT', 'SIGTERM'] as const) {
|
|
49
|
+
process.once(signal, () => {
|
|
50
|
+
void ApplicationServer.close().catch(error => {
|
|
51
|
+
console.error(error);
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Run `bun index.ts` or `node --env-file-if-exists=.env index.ts`. Node requires ESM (`"type": "module"` in package.json). When using Bun, load configuration secrets from the application environment or its `.env` file.
|
|
59
|
+
|
|
60
|
+
## TypeScript and lifecycle
|
|
61
|
+
|
|
62
|
+
Add this type-only import to an application-owned `plugin-types.d.ts` for configuration autocomplete:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import type {} from '@beespoke/micro-server-logger-winston/plugin';
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Core validates plugin options before setup and owns cleanup after successful startup or startup failure. Await `ApplicationServer.bootstrap()` before using the configured client, and call `ApplicationServer.close()` during application shutdown. Importing the package does not open a connection. Relative plugin paths resolve from the selected configuration file's directory.
|
|
69
|
+
|
|
70
|
+
The root export can also be used without HTTP core. In that case, explicitly initialize and close the client. The `/plugin` entry is the integration adapter for `@beespoke/micro-server`.
|
package/dist/Logger.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PluginContext } from './PluginContext.js';
|
|
2
|
+
/** Static methods also satisfy the core's variadic logger contract. */
|
|
3
|
+
export default class Logger {
|
|
4
|
+
readonly name = "logger-winston";
|
|
5
|
+
setup(context: PluginContext): void;
|
|
6
|
+
static info(...args: unknown[]): void;
|
|
7
|
+
static error(...args: unknown[]): void;
|
|
8
|
+
static warn(...args: unknown[]): void;
|
|
9
|
+
static debug(...args: unknown[]): void;
|
|
10
|
+
private static write;
|
|
11
|
+
static table(data: object[]): void;
|
|
12
|
+
static close(): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Structural subset of the core context; standalone clients need no HTTP dependency. */
|
|
2
|
+
export interface Logger {
|
|
3
|
+
info(...args: unknown[]): void;
|
|
4
|
+
warn(...args: unknown[]): void;
|
|
5
|
+
error(...args: unknown[]): void;
|
|
6
|
+
debug(...args: unknown[]): void;
|
|
7
|
+
}
|
|
8
|
+
export interface PluginContext {
|
|
9
|
+
readonly logger: Logger;
|
|
10
|
+
readonly configDir: string;
|
|
11
|
+
onStart(hook: () => void | Promise<void>): void;
|
|
12
|
+
onClose(hook: () => void | Promise<void>): void;
|
|
13
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default, default as Logger } from './Logger.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// src/Logger.ts
|
|
2
|
+
import winston from "winston";
|
|
3
|
+
import Table from "cli-table3";
|
|
4
|
+
var activeLogger;
|
|
5
|
+
var closing;
|
|
6
|
+
function getLogger() {
|
|
7
|
+
if (!activeLogger) {
|
|
8
|
+
const { combine, timestamp, errors, splat, printf, colorize } = winston.format;
|
|
9
|
+
activeLogger = winston.createLogger({
|
|
10
|
+
level: "info",
|
|
11
|
+
format: combine(errors({ stack: true }), timestamp(), colorize(), splat(), printf((info) => {
|
|
12
|
+
const message = typeof info.message === "object" ? JSON.stringify(info.message, null, 3) : info.message;
|
|
13
|
+
return `[${info.level}]${info.timestamp}: ${message}`;
|
|
14
|
+
})),
|
|
15
|
+
transports: [new winston.transports.Console]
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return activeLogger;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class Logger {
|
|
22
|
+
name = "logger-winston";
|
|
23
|
+
setup(context) {
|
|
24
|
+
context.onClose(() => Logger.close());
|
|
25
|
+
}
|
|
26
|
+
static info(...args) {
|
|
27
|
+
Logger.write("info", args);
|
|
28
|
+
}
|
|
29
|
+
static error(...args) {
|
|
30
|
+
Logger.write("error", args);
|
|
31
|
+
}
|
|
32
|
+
static warn(...args) {
|
|
33
|
+
Logger.write("warn", args);
|
|
34
|
+
}
|
|
35
|
+
static debug(...args) {
|
|
36
|
+
Logger.write("debug", args);
|
|
37
|
+
}
|
|
38
|
+
static write(level, args) {
|
|
39
|
+
if (!args.length)
|
|
40
|
+
return;
|
|
41
|
+
const [message, ...details] = args;
|
|
42
|
+
const logger = getLogger();
|
|
43
|
+
if (message instanceof Error && details.length === 0)
|
|
44
|
+
logger[level](message);
|
|
45
|
+
else if (typeof message === "string")
|
|
46
|
+
logger[level](`${message}${details.length ? " %o".repeat(details.length) : ""}`, ...details);
|
|
47
|
+
else
|
|
48
|
+
logger[level]({ message, ...details.length ? { details } : {} });
|
|
49
|
+
}
|
|
50
|
+
static table(data) {
|
|
51
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
52
|
+
Logger.info("No data to display in table.");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const headers = Object.keys(data[0]);
|
|
56
|
+
const table = new Table({
|
|
57
|
+
head: headers,
|
|
58
|
+
wordWrap: true,
|
|
59
|
+
wrapOnWordBoundary: false,
|
|
60
|
+
colWidths: headers.map(() => 30),
|
|
61
|
+
style: { head: ["green"], border: ["grey"] }
|
|
62
|
+
});
|
|
63
|
+
for (const row of data) {
|
|
64
|
+
table.push(headers.map((header) => {
|
|
65
|
+
const value = row[header];
|
|
66
|
+
return typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
Logger.info(`
|
|
70
|
+
` + table.toString());
|
|
71
|
+
}
|
|
72
|
+
static async close() {
|
|
73
|
+
if (closing)
|
|
74
|
+
return closing;
|
|
75
|
+
const logger = activeLogger;
|
|
76
|
+
if (!logger)
|
|
77
|
+
return;
|
|
78
|
+
activeLogger = undefined;
|
|
79
|
+
closing = new Promise((resolve, reject) => {
|
|
80
|
+
const finish = () => {
|
|
81
|
+
logger.removeListener("error", fail);
|
|
82
|
+
logger.close();
|
|
83
|
+
resolve();
|
|
84
|
+
};
|
|
85
|
+
const fail = (error) => {
|
|
86
|
+
logger.removeListener("finish", finish);
|
|
87
|
+
logger.close();
|
|
88
|
+
reject(error);
|
|
89
|
+
};
|
|
90
|
+
logger.once("finish", finish);
|
|
91
|
+
logger.once("error", fail);
|
|
92
|
+
logger.end();
|
|
93
|
+
});
|
|
94
|
+
try {
|
|
95
|
+
await closing;
|
|
96
|
+
} finally {
|
|
97
|
+
closing = undefined;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
Logger as default,
|
|
103
|
+
Logger
|
|
104
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PluginDefinition } from '@beespoke/micro-server';
|
|
2
|
+
export type WinstonPluginOptions = Record<string, never>;
|
|
3
|
+
declare module '@beespoke/micro-server' {
|
|
4
|
+
interface PluginOptionsRegistry {
|
|
5
|
+
'@beespoke/micro-server-logger-winston': WinstonPluginOptions;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
declare const definition: PluginDefinition<WinstonPluginOptions>;
|
|
9
|
+
export default definition;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// src/plugin/index.ts
|
|
2
|
+
import { Logger } from "../index.js";
|
|
3
|
+
var definition = {
|
|
4
|
+
name: "@beespoke/micro-server-logger-winston",
|
|
5
|
+
validate(options) {
|
|
6
|
+
if (!options || typeof options !== "object" || Array.isArray(options) || Object.keys(options).length)
|
|
7
|
+
throw new Error("Winston options must be an empty object");
|
|
8
|
+
},
|
|
9
|
+
create() {
|
|
10
|
+
return {
|
|
11
|
+
name: "logger-winston",
|
|
12
|
+
applicationLogger: Logger,
|
|
13
|
+
setup(context) {
|
|
14
|
+
new Logger().setup(context);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var plugin_default = definition;
|
|
20
|
+
export {
|
|
21
|
+
plugin_default as default
|
|
22
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@beespoke/micro-server-logger-winston",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "2.0.3",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./plugin": {
|
|
14
|
+
"types": "./dist/plugin/index.d.ts",
|
|
15
|
+
"import": "./dist/plugin/index.js",
|
|
16
|
+
"default": "./dist/plugin/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "bun ../../scripts/build-package.ts"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"winston": "^3.13.0",
|
|
27
|
+
"cli-table3": "^0.6.5",
|
|
28
|
+
"@types/node": "^24.0.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"@beespoke/micro-server": "^2.0.3"
|
|
32
|
+
},
|
|
33
|
+
"peerDependenciesMeta": {
|
|
34
|
+
"@beespoke/micro-server": {
|
|
35
|
+
"optional": true
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|