Skip to content
Merged
1 change: 1 addition & 0 deletions extensions/ql-vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Avoid synchronizing the `codeQL.cli.executablePath` setting. [#1252](https://github.com/github/vscode-codeql/pull/1252)
- Open the directory in the finder/explorer (instead of just highlighting it) when running the "Open query directory" command from the query history view. [#1235](https://github.com/github/vscode-codeql/pull/1235)
- Ensure query label in the query history view changes are persisted across restarts. [#1235](https://github.com/github/vscode-codeql/pull/1235)
- Prints end-of-query evaluator log summaries to the Query Server Console. [#1264](https://github.com/github/vscode-codeql/pull/1264)

## 1.6.1 - 17 March 2022

Expand Down
11 changes: 10 additions & 1 deletion extensions/ql-vscode/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -667,15 +667,18 @@ export class CodeQLCliServer implements Disposable {

/**
* Generate a summary of an evaluation log.
* @param endSummaryPath The path to write only the end of query part of the human-readable summary to.
* @param inputPath The path of an evaluation event log.
* @param outputPath The path to write a human-readable summary of it to.
*/
async generateLogSummary(
inputPath: string,
outputPath: string,
endSummaryPath: string,
): Promise<string> {
const subcommandArgs = [
'--format=text',
`--end-summary=${endSummaryPath}`,
inputPath,
outputPath
];
Expand Down Expand Up @@ -1279,8 +1282,14 @@ export class CliVersionConstraint {

/**
* CLI version that supports rotating structured logs to produce one per query.
*
* Note that 2.8.4 supports generating the evaluation logs and summaries,
* but 2.9.0 includes a new option to produce the end-of-query summary logs to
* the query server console. For simplicity we gate all features behind 2.9.0,
* but if a user is tied to the 2.8 release, we can enable evaluator logs
* and summaries for them.
*/
public static CLI_VERSION_WITH_PER_QUERY_EVAL_LOG = new SemVer('2.8.4');
public static CLI_VERSION_WITH_PER_QUERY_EVAL_LOG = new SemVer('2.9.0');

constructor(private readonly cli: CodeQLCliServer) {
/**/
Expand Down
2 changes: 1 addition & 1 deletion extensions/ql-vscode/src/pure/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,7 @@ export interface StartLogResult {
}

/**
* The result of terminating a structured.
* The result of terminating a structured log.
*/
export interface EndLogResult {
/**
Expand Down
14 changes: 8 additions & 6 deletions extensions/ql-vscode/src/query-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -781,6 +781,11 @@ export class QueryHistoryManager extends DisposableObject {
void showAndLogWarningMessage('No evaluator log is available for this run. Perhaps it failed before evaluation, or you are running with a version of CodeQL before ' + CliVersionConstraint.CLI_VERSION_WITH_PER_QUERY_EVAL_LOG + '?');
}

private warnNoEvalLogSummary() {
void showAndLogWarningMessage(`No evaluator log summary is available for this run. Perhaps it failed before evaluation, or you are running with a version of CodeQL before ${CliVersionConstraint.CLI_VERSION_WITH_PER_QUERY_EVAL_LOG}?`);
}


async handleShowEvalLog(
singleItem: QueryHistoryInfo,
multiSelect: QueryHistoryInfo[]
Expand Down Expand Up @@ -810,13 +815,10 @@ export class QueryHistoryManager extends DisposableObject {
return;
}

if (finalSingleItem.evalLogLocation) {
if (!fs.existsSync(finalSingleItem.evalLogSummaryLocation)) {
await this.qs.cliServer.generateLogSummary(finalSingleItem.evalLogLocation, finalSingleItem.evalLogSummaryLocation);
}
await this.tryOpenExternalFile(finalSingleItem.evalLogSummaryLocation);
if (finalSingleItem.evalLogSummaryLocation) {
await this.tryOpenExternalFile(finalSingleItem.evalLogSummaryLocation);
} else {
this.warnNoEvalLog();
this.warnNoEvalLogSummary();
}
}

Expand Down
10 changes: 9 additions & 1 deletion extensions/ql-vscode/src/queryserver-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,14 @@ export function findQueryLogFile(resultPath: string): string {
return path.join(resultPath, 'query.log');
}

export function findQueryStructLogFile(resultPath: string): string {
export function findQueryEvalLogFile(resultPath: string): string {
return path.join(resultPath, 'evaluator-log.jsonl');
}

export function findQueryEvalLogSummaryFile(resultPath: string): string {
return path.join(resultPath, 'evaluator-log.jsonl.summary');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a valid json or jsonl file? If so, it should probably use the proper file extension. Maybe:

Suggested change
return path.join(resultPath, 'evaluator-log.jsonl.summary');
return path.join(resultPath, 'evaluator-log.summary.jsonl');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not — it's a generated text file summarizing the contents of the jsonl file.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK...then maybe avoid the jsonl component entirely?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems agreeable to me, I'll hold to see if @edoardopirovano who named the summary file originally has objections 😸

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just calling it .summary seems perfectly reasonable to me, yep!

}

export function findQueryEvalLogEndSummaryFile(resultPath: string): string {
return path.join(resultPath, 'eoq-evaluator-log.jsonl.summary');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here:

Suggested change
return path.join(resultPath, 'eoq-evaluator-log.jsonl.summary');
return path.join(resultPath, 'eoq-evaluator-log.summary.jsonl');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, it's not a JSONL file but rather a condensed version of the summary text file. I didn't know how to name it so appended eoq to the beginning of the file rather than at the end, but

evaluator-log.jsonl.summary.eoq might also work?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe evaluator-log-end.summary? As I understand it, this is only used internally so I don't suppose it matters too much.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this one now that the jsonl part is gone! Very succinct

}
38 changes: 33 additions & 5 deletions extensions/ql-vscode/src/run-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,16 @@ export class QueryEvaluationInfo {
return qsClient.findQueryLogFile(this.querySaveDir);
}

get structLogPath() {
return qsClient.findQueryStructLogFile(this.querySaveDir);
get evalLogPath() {
return qsClient.findQueryEvalLogFile(this.querySaveDir);
}

get evalLogSummaryPath() {
return qsClient.findQueryEvalLogSummaryFile(this.querySaveDir);
}

get evalLogEndSummaryPath() {
return qsClient.findQueryEvalLogEndSummaryFile(this.querySaveDir);
}

get resultsPaths() {
Expand Down Expand Up @@ -164,8 +172,9 @@ export class QueryEvaluationInfo {
if (queryInfo && await qs.cliServer.cliConstraints.supportsPerQueryEvalLog()) {
await qs.sendRequest(messages.startLog, {
db: dataset,
logPath: this.structLogPath,
logPath: this.evalLogPath,
});

}
const params: messages.EvaluateQueriesParams = {
db: dataset,
Expand All @@ -186,9 +195,21 @@ export class QueryEvaluationInfo {
if (queryInfo && await qs.cliServer.cliConstraints.supportsPerQueryEvalLog()) {
await qs.sendRequest(messages.endLog, {
db: dataset,
logPath: this.structLogPath,
logPath: this.evalLogPath,
});
queryInfo.evalLogLocation = this.structLogPath;
if (await this.hasEvalLog()) {
queryInfo.evalLogLocation = this.evalLogPath;
await qs.cliServer.generateLogSummary(this.evalLogPath, this.evalLogSummaryPath, this.evalLogEndSummaryPath);
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 --- ');
void qs.logger.log(buffer.toString());
});
} else {
void showAndLogWarningMessage(`Failed to write structured evaluator log to ${this.evalLogPath}.`);
}
}
}
return result || {
Expand Down Expand Up @@ -303,6 +324,13 @@ export class QueryEvaluationInfo {
return this.dilPath;
}

/**
* Holds if this query already has a completed structured evaluator log
*/
async hasEvalLog(): Promise<boolean> {
return fs.pathExists(this.evalLogPath);
}

/**
* Creates the CSV file containing the results of this query. This will only be called if the query
* does not have interpreted results and the CSV file does not already exist.
Expand Down