Skip to content
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
11 changes: 10 additions & 1 deletion extensions/ql-vscode/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ export class CodeQLCliServer implements Disposable {
const subcommandArgs = [
'--format=text',
`--end-summary=${endSummaryPath}`,
'--sourcemap',
...(await this.cliConstraints.supportsSourceMap() ? ['--sourcemap'] : []),
inputPath,
outputPath
];
Expand Down Expand Up @@ -1322,6 +1322,11 @@ export class CliVersionConstraint {
*/
public static CLI_VERSION_WITH_PER_QUERY_EVAL_LOG = new SemVer('2.9.0');

/**
* CLI version that supports the `--sourcemap` option for log generation.
*/
public static CLI_VERSION_WITH_SOURCEMAP = new SemVer('2.10.3');

constructor(private readonly cli: CodeQLCliServer) {
/**/
}
Expand Down Expand Up @@ -1389,4 +1394,8 @@ export class CliVersionConstraint {
async supportsPerQueryEvalLog() {
return this.isVersionAtLeast(CliVersionConstraint.CLI_VERSION_WITH_PER_QUERY_EVAL_LOG);
}

async supportsSourceMap() {
return this.isVersionAtLeast(CliVersionConstraint.CLI_VERSION_WITH_SOURCEMAP);
}
}
58 changes: 38 additions & 20 deletions extensions/ql-vscode/src/run-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { compileDatabaseUpgradeSequence, hasNondestructiveUpgradeCapabilities, u
import { ensureMetadataIsComplete } from './query-results';
import { SELECT_QUERY_NAME } from './contextual/locationFinder';
import { DecodedBqrsChunk } from './pure/bqrs-cli-types';
import { getErrorMessage } from './pure/helpers-pure';
import { asError, getErrorMessage } from './pure/helpers-pure';
import { generateSummarySymbolsFile } from './log-insights/summary-parser';

/**
Expand Down Expand Up @@ -207,7 +207,10 @@ export class QueryEvaluationInfo {
logPath: this.evalLogPath,
});
if (await this.hasEvalLog()) {
this.displayHumanReadableLogSummary(queryInfo, qs);
queryInfo.evalLogLocation = this.evalLogPath;
queryInfo.evalLogSummaryLocation = await this.generateHumanReadableLogSummary(qs);
void this.logEndSummary(queryInfo.evalLogSummaryLocation, qs); // Logged asynchrnously

if (config.isCanary()) { // Generate JSON summary for viewer.
await qs.cliServer.generateJsonLogSummary(this.evalLogPath, this.jsonEvalLogSummaryPath);
queryInfo.jsonEvalLogSummaryLocation = this.jsonEvalLogSummaryPath;
Expand Down Expand Up @@ -340,25 +343,40 @@ export class QueryEvaluationInfo {
}

/**
* Calls the appropriate CLI command to generate a human-readable log summary
* and logs to the Query Server console and query log file.
* Calls the appropriate CLI command to generate a human-readable log summary.
* @param qs The query server client.
* @returns The path to the log summary, or `undefined` if the summary could not be generated.
*/
displayHumanReadableLogSummary(queryInfo: LocalQueryInfo, qs: qsClient.QueryServerClient): void {
queryInfo.evalLogLocation = this.evalLogPath;
void qs.cliServer.generateLogSummary(this.evalLogPath, this.evalLogSummaryPath, this.evalLogEndSummaryPath)
.then(() => {
queryInfo.evalLogSummaryLocation = this.evalLogSummaryPath;
fs.readFile(this.evalLogEndSummaryPath, (err, buffer) => {
if (err) {
throw new Error(`Could not read structured evaluator log end of summary file at ${this.evalLogEndSummaryPath}.`);
}
void qs.logger.log(' --- Evaluator Log Summary --- ', { additionalLogLocation: this.logPath });
void qs.logger.log(buffer.toString(), { additionalLogLocation: this.logPath });
});
})
.catch(err => {
void showAndLogWarningMessage(`Failed to generate human-readable structured evaluator log summary. Reason: ${err.message}`);
});
private async generateHumanReadableLogSummary(qs: qsClient.QueryServerClient): Promise<string | undefined> {
try {
await qs.cliServer.generateLogSummary(this.evalLogPath, this.evalLogSummaryPath, this.evalLogEndSummaryPath);
return this.evalLogSummaryPath;

} catch (e) {
const err = asError(e);
void showAndLogWarningMessage(`Failed to generate human-readable structured evaluator log summary. Reason: ${err.message}`);
return undefined;
}
}

/**
* Logs the end summary to the Output window and log file.
* @param logSummaryPath Path to the human-readable log summary
* @param qs The query server client.
*/
private async logEndSummary(logSummaryPath: string | undefined, qs: qsClient.QueryServerClient): Promise<void> {
if (logSummaryPath === undefined) {
// Failed to generate the log, so we don't expect an end summary either.
return;
}

try {
const endSummaryContent = await fs.readFile(this.evalLogEndSummaryPath, 'utf-8');
void qs.logger.log(' --- Evaluator Log Summary --- ', { additionalLogLocation: this.logPath });
void qs.logger.log(endSummaryContent, { additionalLogLocation: this.logPath });
} catch (e) {
void showAndLogWarningMessage(`Could not read structured evaluator log end of summary file at ${this.evalLogEndSummaryPath}.`);
}
}

/**
Expand Down