Skip to content

Commit 96129a9

Browse files
committed
fix(logging): normalize lint logger output to single-line events
Remove empty logger payload emission from eslint formatter output. Flatten multiline and indentation-style logger payloads into single-line events and keep human-readable wording.
1 parent f51468a commit 96129a9

7 files changed

Lines changed: 106 additions & 34 deletions

File tree

src/bin/matrixai-lint.ts

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ function printDomainList(
9696
): void {
9797
logger.info('Available lint domains:');
9898
for (const domainInfo of domains) {
99-
logger.info(`- ${domainInfo.domain}: ${domainInfo.description}`);
99+
logger.info(
100+
`Domain info: domain=${domainInfo.domain} description=${domainInfo.description}`,
101+
);
100102
}
101103
}
102104

@@ -106,24 +108,20 @@ function printExplain(
106108
): void {
107109
logger.info('[matrixai-lint] Domain execution plan:');
108110
for (const decision of decisions) {
109-
logger.info(`[matrixai-lint] - domain: ${decision.domain}`);
110-
logger.info(
111-
`[matrixai-lint] selection: ${decision.selectionSource}${decision.explicitlyRequested ? ' (explicit)' : ''}`,
112-
);
111+
logger.info(`[matrixai-lint] domain=${decision.domain}`);
113112
logger.info(
114-
`[matrixai-lint] relevance: ${describeRelevance(decision)}`,
113+
`[matrixai-lint] selection=${decision.selectionSource}${decision.explicitlyRequested ? ' (explicit)' : ''}`,
115114
);
115+
logger.info(`[matrixai-lint] relevance=${describeRelevance(decision)}`);
116116
logger.info(
117-
`[matrixai-lint] availability: ${describeAvailability(decision)}`,
117+
`[matrixai-lint] availability=${describeAvailability(decision)}`,
118118
);
119119
if (decision.detectionError != null) {
120120
logger.error(
121-
`[matrixai-lint] detection-error: ${decision.detectionError}`,
121+
`[matrixai-lint] detection-error=${decision.detectionError}`,
122122
);
123123
}
124-
logger.info(
125-
`[matrixai-lint] planned-action: ${decision.plannedAction}`,
126-
);
124+
logger.info(`[matrixai-lint] planned-action=${decision.plannedAction}`);
127125
}
128126
}
129127

@@ -227,10 +225,10 @@ async function main(argv = process.argv) {
227225
}
228226

229227
if (hadFailure) {
230-
logger.error('[matrixai-lint] Linting failed.');
228+
logger.error('[matrixai-lint] Linting failed.');
231229
process.exit(1);
232230
} else {
233-
logger.info('[matrixai-lint] Linting passed.');
231+
logger.info('[matrixai-lint] Linting passed.');
234232
}
235233
}
236234

src/domains/engine.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ type LintDomainPlugin = {
6868
) => LintDomainPluginResult);
6969
};
7070

71+
function normalizeLogDetail(value: unknown): string {
72+
return String(value)
73+
.replace(/\r?\n+/g, ' | ')
74+
.trim();
75+
}
76+
7177
function createLintDomainRegistry(
7278
plugins: readonly LintDomainPlugin[],
7379
): Map<LintDomain, LintDomainPlugin> {
@@ -212,7 +218,7 @@ async function runLintDomainDecisions({
212218
}
213219

214220
if (plannedAction === 'fail-detection') {
215-
const message = `[matrixai-lint] - Domain "${domain}" failed unexpectedly.\n${detectionError ?? 'Unknown detection error.'}`;
221+
const message = `[matrixai-lint] - Domain "${domain}" failed unexpectedly. ${normalizeLogDetail(detectionError ?? 'Unknown detection error.')}`;
216222
logger.error(message);
217223
hadFailure = true;
218224
continue;
@@ -222,7 +228,7 @@ async function runLintDomainDecisions({
222228
if (explicitlyRequested) {
223229
const relevanceReason =
224230
detection?.relevanceReason ?? 'No files matched in effective scope.';
225-
const message = `[matrixai-lint] - Domain "${domain}" was explicitly requested, but no files matched. ${relevanceReason}`;
231+
const message = `[matrixai-lint] - Domain "${domain}" was explicitly requested, but no files matched. ${relevanceReason}`;
226232
logger.warn(message);
227233
}
228234
continue;
@@ -232,7 +238,7 @@ async function runLintDomainDecisions({
232238
const unavailableReason =
233239
detection?.unavailableReason ??
234240
`Tooling for domain "${domain}" is not available.`;
235-
const message = `[matrixai-lint] - Domain "${domain}" cannot run. ${unavailableReason}`;
241+
const message = `[matrixai-lint] - Domain "${domain}" cannot run. ${unavailableReason}`;
236242
logger.error(message);
237243
hadFailure = true;
238244
continue;
@@ -242,7 +248,7 @@ async function runLintDomainDecisions({
242248
const unavailableReason =
243249
detection?.unavailableReason ??
244250
`Tooling for domain "${domain}" is not available.`;
245-
const message = `[matrixai-lint] - Domain "${domain}" skipped. ${unavailableReason}`;
251+
const message = `[matrixai-lint] - Domain "${domain}" skipped. ${unavailableReason}`;
246252
logger.warn(message);
247253
continue;
248254
}
@@ -253,7 +259,7 @@ async function runLintDomainDecisions({
253259
}
254260

255261
if (detection == null) {
256-
const message = `[matrixai-lint] - Domain "${domain}" is missing detection metadata.`;
262+
const message = `[matrixai-lint] - Domain "${domain}" is missing detection metadata.`;
257263
logger.error(message);
258264
hadFailure = true;
259265
continue;
@@ -265,7 +271,7 @@ async function runLintDomainDecisions({
265271
hadFailure = true;
266272
}
267273
} catch (err) {
268-
const message = `[matrixai-lint] - Domain "${domain}" failed unexpectedly.\n${String(err)}`;
274+
const message = `[matrixai-lint] - Domain "${domain}" failed unexpectedly. ${normalizeLogDetail(err)}`;
269275
logger.error(message);
270276
hadFailure = true;
271277
}

src/domains/eslint.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ import {
66
import * as utils from '../utils.js';
77
import { resolveLintConfig } from '../config.js';
88

9+
function normalizeLogDetail(value: unknown): string {
10+
return String(value)
11+
.replace(/\r?\n+/g, ' | ')
12+
.trim();
13+
}
14+
915
const ESLINT_FILE_EXTENSIONS = [
1016
'.js',
1117
'.mjs',
@@ -109,7 +115,12 @@ function createESLintDomainPlugin(): LintDomainPlugin {
109115

110116
return { hadFailure: hadLintingErrors };
111117
} catch (err) {
112-
logger.error(`ESLint failed: \n${err}`);
118+
const errorDetail = normalizeLogDetail(err);
119+
logger.error(
120+
errorDetail.length > 0
121+
? `ESLint failed. ${errorDetail}`
122+
: 'ESLint failed.',
123+
);
113124
return { hadFailure: true };
114125
}
115126
},

src/domains/markdown.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ const DEFAULT_MARKDOWN_SEARCH_ROOTS = [
1717
'./docs',
1818
];
1919

20+
function normalizeLogDetail(value: unknown): string {
21+
return String(value)
22+
.replace(/\r?\n+/g, ' | ')
23+
.trim();
24+
}
25+
2026
function collectMarkdownFilesFromScope(patterns: readonly string[]): string[] {
2127
const matchedRelativeFiles = resolveFilesFromPatterns(
2228
patterns,
@@ -92,7 +98,9 @@ function createMarkdownDomainPlugin({
9298

9399
try {
94100
if (prettierBin) {
95-
logger.info(` ${prettierBin} \n ${prettierArgs.join('\n' + ' ')}`);
101+
logger.info(
102+
`Running prettier command: ${process.execPath} ${prettierBin} ${prettierArgs.join(' ')}`,
103+
);
96104
childProcess.execFileSync(
97105
process.execPath,
98106
[prettierBin, ...prettierArgs],
@@ -104,7 +112,9 @@ function createMarkdownDomainPlugin({
104112
},
105113
);
106114
} else {
107-
logger.info('prettier ' + prettierArgs.join('\n' + ' '));
115+
logger.info(
116+
`Running prettier command: prettier ${prettierArgs.join(' ')}`,
117+
);
108118
childProcess.execFileSync('prettier', prettierArgs, {
109119
stdio: 'inherit',
110120
windowsHide: true,
@@ -114,10 +124,19 @@ function createMarkdownDomainPlugin({
114124
});
115125
}
116126
} catch (err) {
127+
const errorDetail = normalizeLogDetail(err);
117128
if (!fix) {
118-
logger.error('Prettier check failed.');
129+
logger.error(
130+
errorDetail.length > 0
131+
? `Prettier check failed. ${errorDetail}`
132+
: 'Prettier check failed.',
133+
);
119134
} else {
120-
logger.error('Prettier write failed. ' + err);
135+
logger.error(
136+
errorDetail.length > 0
137+
? `Prettier write failed. ${errorDetail}`
138+
: 'Prettier write failed.',
139+
);
121140
}
122141

123142
return { hadFailure: true };

src/domains/shell.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ const platform = os.platform();
99

1010
const SHELL_FILE_EXTENSIONS = ['.sh'] as const;
1111

12+
function normalizeLogDetail(value: unknown): string {
13+
return String(value)
14+
.replace(/\r?\n+/g, ' | ')
15+
.trim();
16+
}
17+
1218
function resolveShellPatterns(
1319
shellPatterns: readonly string[] | undefined,
1420
defaultSearchRoots: readonly string[],
@@ -55,7 +61,9 @@ function createShellDomainPlugin({
5561
}
5662

5763
logger.info('Running shellcheck:');
58-
logger.info(' ' + ['shellcheck', ...matchedFiles].join(' '));
64+
logger.info(
65+
`Running shellcheck command: shellcheck ${matchedFiles.join(' ')}`,
66+
);
5967

6068
try {
6169
childProcess.execFileSync('shellcheck', matchedFiles, {
@@ -68,7 +76,12 @@ function createShellDomainPlugin({
6876

6977
return { hadFailure: false };
7078
} catch (err) {
71-
logger.error('Shellcheck failed. ' + err);
79+
const errorDetail = normalizeLogDetail(err);
80+
logger.error(
81+
errorDetail.length > 0
82+
? `Shellcheck failed. ${errorDetail}`
83+
: 'Shellcheck failed.',
84+
);
7285
return { hadFailure: true };
7386
}
7487
},

src/utils.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,9 @@ async function runESLint({
7272
// PATH A - user supplied explicit globs
7373
if (explicitGlobs?.length) {
7474
logger.info('Linting with explicit patterns:');
75-
explicitGlobs.forEach((g) => logger.info(' ' + g));
75+
explicitGlobs.forEach((pattern) => {
76+
logger.info(`Linting: ${pattern}`);
77+
});
7678

7779
const eslint = new ESLint({
7880
overrideConfigFile: configPath || defaultConfigPath,
@@ -93,12 +95,14 @@ async function runESLint({
9395
const { forceInclude, tsconfigPaths } = lintConfig.domains.eslint;
9496

9597
if (tsconfigPaths.length === 0) {
96-
logger.error('[matrixai-lint] No tsconfig.json files found.');
98+
logger.error('[matrixai-lint] No tsconfig.json files found.');
9799
return true;
98100
}
99101

100102
logger.info(`Found ${tsconfigPaths.length} tsconfig.json files:`);
101-
tsconfigPaths.forEach((p) => logger.info(' ' + p));
103+
tsconfigPaths.forEach((tsconfigPath) => {
104+
logger.info(`Using tsconfig: ${tsconfigPath}`);
105+
});
102106

103107
const { files: patterns, ignore: ignorePats } = buildPatterns(
104108
tsconfigPaths,
@@ -109,13 +113,15 @@ async function runESLint({
109113

110114
if (patterns.length === 0) {
111115
logger.warn(
112-
'[matrixai-lint] No ESLint targets were derived from configured tsconfig paths.',
116+
'[matrixai-lint] No ESLint targets were derived from configured tsconfig paths.',
113117
);
114118
return false;
115119
}
116120

117121
logger.info('Linting files:');
118-
patterns.forEach((p) => logger.info(' ' + p));
122+
patterns.forEach((pattern) => {
123+
logger.info(`Linting: ${pattern}`);
124+
});
119125

120126
const eslint = new ESLint({
121127
overrideConfigFile: configPath || defaultConfigPath,
@@ -144,9 +150,28 @@ async function lintAndReport(
144150
await ESLint.outputFixes(results);
145151
}
146152

153+
const errorCount = results.reduce(
154+
(sum, result) => sum + result.errorCount,
155+
0,
156+
);
157+
const warningCount = results.reduce(
158+
(sum, result) => sum + result.warningCount,
159+
0,
160+
);
161+
logger.info(
162+
`ESLint summary: files=${results.length} errors=${errorCount} warnings=${warningCount} fix=${fix ? 'on' : 'off'}`,
163+
);
164+
147165
const formatter = await eslint.loadFormatter('stylish');
148-
logger.info(formatter.format(results));
149-
const hasErrors = results.some((r) => r.errorCount > 0);
166+
const formattedOutput = await formatter.format(results);
167+
for (const line of formattedOutput.split(/\r?\n/)) {
168+
const normalizedLine = line.trim();
169+
if (normalizedLine.length > 0) {
170+
logger.info(`ESLint detail: ${normalizedLine}`);
171+
}
172+
}
173+
174+
const hasErrors = errorCount > 0;
150175

151176
return hasErrors;
152177
}

tests/bin/lint.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ describe('matrixai-lint CLI domain semantics', () => {
265265
);
266266
expect(stderrWriteSpy).toHaveBeenCalledWith(
267267
expect.stringContaining(
268-
'INFO:matrixai-lint:[matrixai-lint] - domain: markdown',
268+
'INFO:matrixai-lint:[matrixai-lint] domain=markdown',
269269
),
270270
);
271271
expect(stderrWriteSpy).toHaveBeenCalledWith(

0 commit comments

Comments
 (0)