Skip to content

Conversation

@rmohan20
Copy link
Contributor

@rmohan20 rmohan20 commented Aug 10, 2022

This PR helps provide more insight into how SFGE's analysis is progressing.

  1. ProgressListener is a new class that observes various steps in SFGE's analysis and posts messages to CliMessager. To help control how often path progress updates are provided, SFGE_PROGRESS_INCREMENTS_ON_VERBOSE env variable can be tweaked. Default value is 50.
  2. CliMessagerAppender is a new custom log appender that takes log4j events and translates them into CliMessager posts. This treats Warnings as Info, Errors as Warnings, and Fatal as Errors to keep output information relevant. Also, by default, Warnings are turned off for all users and can be turned on using SFGE_LOG_WARNINGS_ON_VERBOSE env variable.
  3. Typescript and CliMessager layers have been modified to post messages in realtime. Messaging behavior for existing posts remains intact.
  4. Relevant tests

There's still some verbosity coming in while generating catalogs to use for rule execution and this decreases the clarity of SFGE's actual progress. I've logged a separate work item to address this issue.

* @param eventKey EventKey to display to user
* @param args String args passed to the EventKey to make the displayed message meaningful
*/
public static void postMessage(String internalLog, EventKey eventKey, String... args) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Creating an alternate method to post realtime messages. I've marked the other entry points as deprecated and we can eventually make them realtime as well.




/** SFGE RELATED **/
Copy link
Contributor Author

Choose a reason for hiding this comment

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

New event keys to match the new messages

Comment on lines 10 to 18
"unmatchedPathExtensionCpd": "Path extensions for the following files will not be processed by CPD: %s",
"sfgeInfoLog": "%s",
"sfgeMetaInfoCollected": "Loaded %s: [ %s ]",
"sfgeFinishedCompilingFiles": "Compiled %s files.",
"sfgeStartedBuildingGraph": "Building graph . . .",
"sfgeFinishedBuildingGraph": "Added all compilation units to graph.",
"sfgePathEntryPointsIdentified": "Identified %s path entry point(s).",
"sfgeViolationsInPathProgress": "Detected %s violation(s) from %s path(s) on %s entry point(s) so far.",
"sfgeCompletedPathAnalysis": "Overall, analyzed %s path(s) from %s entry point(s). Detected %s violation(s)."
Copy link
Contributor Author

Choose a reason for hiding this comment

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

New messages to be displayed during verbose calls.
@teresa-allen-sfdc Please do let me your thoughts on the verbose messages.

name = "CliMessagerAppender",
category = Core.CATEGORY_NAME,
elementType = Appender.ELEMENT_TYPE)
public class CliMessagerAppender extends AbstractAppender {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

New log appender that steps in to pass realtime messages when needed.


/** Indicates if a Jorje parse error causes the entire process to stop. */
boolean shouldIgnoreParseErrors();

Copy link
Contributor Author

Choose a reason for hiding this comment

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

New config values to control verbose behavior.
LogWarningsOnVerbose would make the output noisier by including all the warnings from SFGE as info events.
ProgressIncrementsOnVerbose controls how often we post updates on number of paths analyzed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need these config values anymore? Would removing them simplify the code?

import java.util.Set;
import java.util.TreeSet;

public interface ProgressListener {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will add javadocs

import java.util.TreeSet;

/** Publishes information to CLI on the progress of analysis. */
public class ProgressListenerImpl implements ProgressListener {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

All action happens here

Comment on lines +5 to +7
<CliMessagerAppender name="LogToCliMessager">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %m%n"/>
</CliMessagerAppender>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Configuring the new log appender.

// When data is passed back up to us, pop it onto the appropriate string.
cp.stdout.on('data', data => {
stdout += data;
if (!this.handleLiveOut(String(data))) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Handle live output if relevant.

Comment on lines +103 to +114
const regex = new RegExp(`^${startTag}(.*)${endTag}`, 'g');
const headerLength = startTag.length;
const tailLength = endTag.length;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Steps are the same as regular CliMessager updates, except we allow different tags to mean different things.

Comment on lines 235 to 238
if (this.outputProcessor.isRealtimeOutput(data)) {
return this.outputProcessor.processRealtimeOutput(data);
}
return false;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

SFGE overrides live output handling.

expect(isSubstr(output, substring), `Output "${output}" should not contain substring "${substring}"`).is.false;
}

describe('scanner:run:dfa', function () {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

New end-to-end tests for dfa. Directly testing sfge's Main.java was getting problematic because of the multithreading. These new tests are more reliable.
Though I'm seeing an issue where each verbose like is printed 6 times. Still investigating to understand the cause.

@rmohan20 rmohan20 marked this pull request as ready for review August 11, 2022 21:37
Copy link
Contributor

@jfeingold35 jfeingold35 left a comment

Choose a reason for hiding this comment

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

The SFGE portion has more than we strictly need, but the design itself is sound. I'll keep an eye out for the refactor.

Comment on lines 24 to 30
boolean shouldLogWarningsOnVerbose();

/**
* Should be used to set the level of increments at which path analysis progress update is
* provided
*/
int getProgressIncrementsOnVerbose();
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary, since we're making the progress report happen all the time instead of just on Verbose.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since the functionality has been modified, this can be renamed to not include "OnVerbose". Though I still think this is a useful variable to have so that users could increase or decrease depending on their convenience. For now, I haven't surfaced these new variables as scanner:run:dfa's flags.

Comment on lines 27 to 28
@VisibleForTesting static final boolean DEFAULT_LOG_WARNINGS_ON_VERBOSE = false;
@VisibleForTesting static final int DEFAULT_PROGRESS_INCREMENTS_ON_VERBOSE = 50;
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary, since progress logging should happen all the time instead of just on Verbose.

Comment on lines 29 to 37
public boolean shouldLogWarningsOnVerbose() {
return EnvUtil.shouldLogWarningsOnVerbose();
}

@Override
public int getProgressIncrementsOnVerbose() {
return EnvUtil.getProgressIncrementsOnVerbose();
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary.

}
}

final ProgressListener progressListener = ProgressListenerProvider.get();
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we have the listener be a static final property to avoid the need to keep declaring a variable for it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

static final would force instantiation at the earliest and not use the lazy loading functionality as intended.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

*/
public class ProgressListenerImpl implements ProgressListener {

@VisibleForTesting static final String NONE_FOUND = "none found";
Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned in scrum, having this many individual events feels like overkill for now, but the strategy itself is sound.

Comment on lines 46 to 52
public boolean shouldLogWarningsOnVerbose() {
return !EnvUtil.DEFAULT_LOG_WARNINGS_ON_VERBOSE;
}

@Override
public int getProgressIncrementsOnVerbose() {
return -1 * EnvUtil.DEFAULT_PROGRESS_INCREMENTS_ON_VERBOSE;
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary

Comment on lines 29 to 34
public boolean shouldLogWarningsOnVerbose() {
return SfgeConfigImpl.getInstance().shouldLogWarningsOnVerbose();
}

@Override
public int getProgressIncrementsOnVerbose() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Unnecessary

"sfgeInfoLog": "%s",
"sfgeMetaInfoCollected": "Loaded %s: [ %s ]",
"sfgeFinishedCompilingFiles": "Compiled %s files.",
"sfgeStartedBuildingGraph": "Building graph . . .",
Copy link
Contributor

Choose a reason for hiding this comment

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

The periods don't need spaces between them.

Comment on lines 75 to 87
static boolean shouldLogWarningsOnVerbose() {
return getBoolOrDefault(ENV_LOG_WARNINGS_ON_VERBOSE, DEFAULT_LOG_WARNINGS_ON_VERBOSE);
}

/**
* Gets the level of increments at which path analysis progress update is provided. Applicable
* only with --verbose.
*
* @return value of {@link #ENV_PROGRESS_INCREMENTS_ON_VERBOSE} environment variable if set,
* else {@link #DEFAULT_PROGRESS_INCREMENTS_ON_VERBOSE}
*/
static int getProgressIncrementsOnVerbose() {
return getIntOrDefault(
ENV_PROGRESS_INCREMENTS_ON_VERBOSE, DEFAULT_PROGRESS_INCREMENTS_ON_VERBOSE);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this still here? We don't need it anymore, right?


/** Indicates if a Jorje parse error causes the entire process to stop. */
boolean shouldIgnoreParseErrors();

Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need these config values anymore? Would removing them simplify the code?

// When data is passed back up to us, pop it onto the appropriate string.
cp.stdout.on('data', data => {
stdout += data;
if (!this.handleLiveOut(String(data))) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't love this check.
If live output and at-the-end output use different start and end strings, couldn't we just pass all output through both at the appropriate times? The output processor would process real time output as it's received, and then it would process at-the-end output at the end, right?

let intervalCount = 0;
this.intervalId = setInterval(() => {
uxEvents.emit(EVENTS.UPDATE_SPINNER, "Please wait." + ".".repeat(intervalCount));
uxEvents.emit(EVENTS.WAIT_ON_SPINNER, 'message is unused');
Copy link
Contributor

Choose a reason for hiding this comment

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

You can remove everything with the interval, here. The point of this was to add a period to the end of the please wait string every 30 seconds. Now that we're adding more informative progress reports, this is redundant.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The extra dots still look like something is happening especially when waiting on the next update. Let me know how you like it during QA. Based on that, we can keep it or remove it.



private emitUxEvent(eventType: string, messageKey: string, args: string[]): void {
if (eventType === '') {
Copy link
Contributor

Choose a reason for hiding this comment

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

How can this happen?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Previously, we had an if/else to filter only valid eventTypes to go in. The filter has been restructured to not always check for eventTypes. This check should possibly never be invoked, but this is just being defensive to avoid unexpected issues.

@rmohan20 rmohan20 force-pushed the rm/returnTimelyResults branch from 4d68616 to 805ca8c Compare August 15, 2022 23:26
@jfeingold35 jfeingold35 merged commit 566a0b6 into dev-3 Aug 16, 2022
@stephen-carter-at-sf stephen-carter-at-sf deleted the rm/returnTimelyResults branch May 17, 2024 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants