create-forgeon 0.1.30 → 0.1.32
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/package.json
CHANGED
|
@@ -299,6 +299,12 @@ describe('addModule', () => {
|
|
|
299
299
|
assert.match(apiDockerfile, /COPY packages\/logger packages\/logger/);
|
|
300
300
|
assert.match(apiDockerfile, /RUN pnpm --filter @forgeon\/logger build/);
|
|
301
301
|
|
|
302
|
+
const loggerTsconfig = fs.readFileSync(
|
|
303
|
+
path.join(projectRoot, 'packages', 'logger', 'tsconfig.json'),
|
|
304
|
+
'utf8',
|
|
305
|
+
);
|
|
306
|
+
assert.match(loggerTsconfig, /"extends": "\.\.\/\.\.\/tsconfig\.base\.node\.json"/);
|
|
307
|
+
|
|
302
308
|
const apiEnv = fs.readFileSync(path.join(projectRoot, 'apps', 'api', '.env.example'), 'utf8');
|
|
303
309
|
assert.match(apiEnv, /LOGGER_LEVEL=log/);
|
|
304
310
|
assert.match(apiEnv, /LOGGER_HTTP_ENABLED=true/);
|
|
@@ -317,6 +323,11 @@ describe('addModule', () => {
|
|
|
317
323
|
assert.match(compose, /LOGGER_HTTP_ENABLED: \$\{LOGGER_HTTP_ENABLED\}/);
|
|
318
324
|
assert.match(compose, /LOGGER_REQUEST_ID_HEADER: \$\{LOGGER_REQUEST_ID_HEADER\}/);
|
|
319
325
|
|
|
326
|
+
const rootReadme = fs.readFileSync(path.join(projectRoot, 'README.md'), 'utf8');
|
|
327
|
+
assert.match(rootReadme, /## Logger Module/);
|
|
328
|
+
assert.match(rootReadme, /LOGGER_LEVEL=log/);
|
|
329
|
+
assert.match(rootReadme, /docker compose logs api/);
|
|
330
|
+
|
|
320
331
|
const moduleDoc = fs.readFileSync(result.docsPath, 'utf8');
|
|
321
332
|
assert.match(moduleDoc, /Logger/);
|
|
322
333
|
assert.match(moduleDoc, /Status: implemented/);
|
package/src/modules/logger.mjs
CHANGED
|
@@ -218,6 +218,44 @@ function patchCompose(targetRoot) {
|
|
|
218
218
|
fs.writeFileSync(composePath, `${content.trimEnd()}\n`, 'utf8');
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
+
function patchReadme(targetRoot) {
|
|
222
|
+
const readmePath = path.join(targetRoot, 'README.md');
|
|
223
|
+
if (!fs.existsSync(readmePath)) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const marker = '## Logger Module';
|
|
228
|
+
let content = fs.readFileSync(readmePath, 'utf8').replace(/\r\n/g, '\n');
|
|
229
|
+
if (content.includes(marker)) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const section = `## Logger Module
|
|
234
|
+
|
|
235
|
+
The logger add-module provides:
|
|
236
|
+
- request id middleware (default header: \`x-request-id\`)
|
|
237
|
+
- HTTP access logs with method/path/status/duration/ip/requestId
|
|
238
|
+
- Nest logger integration via \`app.useLogger(...)\`
|
|
239
|
+
|
|
240
|
+
Configuration (env):
|
|
241
|
+
- \`LOGGER_LEVEL=log\` (\`error|warn|log|debug|verbose\`)
|
|
242
|
+
- \`LOGGER_HTTP_ENABLED=true\`
|
|
243
|
+
- \`LOGGER_REQUEST_ID_HEADER=x-request-id\`
|
|
244
|
+
|
|
245
|
+
Where to see logs:
|
|
246
|
+
- local dev: API terminal output
|
|
247
|
+
- Docker: \`docker compose logs api\`
|
|
248
|
+
`;
|
|
249
|
+
|
|
250
|
+
if (content.includes('## Prisma In Docker Start')) {
|
|
251
|
+
content = content.replace('## Prisma In Docker Start', `${section}\n## Prisma In Docker Start`);
|
|
252
|
+
} else {
|
|
253
|
+
content = `${content.trimEnd()}\n\n${section}\n`;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
fs.writeFileSync(readmePath, `${content.trimEnd()}\n`, 'utf8');
|
|
257
|
+
}
|
|
258
|
+
|
|
221
259
|
export function applyLoggerModule({ packageRoot, targetRoot }) {
|
|
222
260
|
copyFromPreset(packageRoot, targetRoot, path.join('packages', 'logger'));
|
|
223
261
|
patchApiPackage(targetRoot);
|
|
@@ -225,6 +263,7 @@ export function applyLoggerModule({ packageRoot, targetRoot }) {
|
|
|
225
263
|
patchAppModule(targetRoot);
|
|
226
264
|
patchApiDockerfile(targetRoot);
|
|
227
265
|
patchCompose(targetRoot);
|
|
266
|
+
patchReadme(targetRoot);
|
|
228
267
|
|
|
229
268
|
upsertEnvLines(path.join(targetRoot, 'apps', 'api', '.env.example'), [
|
|
230
269
|
'LOGGER_LEVEL=log',
|
|
@@ -238,4 +277,3 @@ export function applyLoggerModule({ packageRoot, targetRoot }) {
|
|
|
238
277
|
'LOGGER_REQUEST_ID_HEADER=x-request-id',
|
|
239
278
|
]);
|
|
240
279
|
}
|
|
241
|
-
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common';
|
|
2
|
-
import { Observable
|
|
2
|
+
import { Observable } from 'rxjs';
|
|
3
3
|
import { ForgeonLoggerService } from './forgeon-logger.service';
|
|
4
4
|
import { LoggerConfigService } from './logger-config.service';
|
|
5
5
|
|
|
@@ -17,6 +17,7 @@ interface RequestLike {
|
|
|
17
17
|
|
|
18
18
|
interface ResponseLike {
|
|
19
19
|
statusCode?: number;
|
|
20
|
+
once?: (event: string, listener: () => void) => void;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
@Injectable()
|
|
@@ -46,30 +47,34 @@ export class ForgeonHttpLoggingInterceptor implements NestInterceptor {
|
|
|
46
47
|
request.requestId ?? this.readHeader(request.headers, this.loggerConfig.requestIdHeader);
|
|
47
48
|
const startedAt = Date.now();
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
50
|
+
if (typeof response.once === 'function') {
|
|
51
|
+
response.once('finish', () => {
|
|
52
|
+
this.logger.logHttpRequest({
|
|
53
|
+
method,
|
|
54
|
+
path,
|
|
55
|
+
statusCode: response.statusCode ?? 200,
|
|
56
|
+
durationMs: Date.now() - startedAt,
|
|
57
|
+
requestId,
|
|
58
|
+
ip,
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
} else {
|
|
62
|
+
// Fallback for non-standard response mocks.
|
|
63
|
+
try {
|
|
64
|
+
this.logger.logHttpRequest({
|
|
65
|
+
method,
|
|
66
|
+
path,
|
|
67
|
+
statusCode: response.statusCode ?? 200,
|
|
68
|
+
durationMs: Date.now() - startedAt,
|
|
69
|
+
requestId,
|
|
70
|
+
ip,
|
|
71
|
+
});
|
|
72
|
+
} catch {
|
|
73
|
+
// no-op
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return next.handle();
|
|
73
78
|
}
|
|
74
79
|
|
|
75
80
|
private readHeader(headers: HeadersRecord | undefined, name: string): string | undefined {
|
|
@@ -87,4 +92,3 @@ export class ForgeonHttpLoggingInterceptor implements NestInterceptor {
|
|
|
87
92
|
return undefined;
|
|
88
93
|
}
|
|
89
94
|
}
|
|
90
|
-
|