Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor console logs to render on server and use virtualization #3075

Merged
merged 6 commits into from
Mar 26, 2024

Conversation

JamesNK
Copy link
Member

@JamesNK JamesNK commented Mar 21, 2024

Fixes #2507

  • Move sorting and rendering to the server
  • Enable virtualization

TODO:

  • Line numbers need work. Especially if the total logs are truncated. For example, if logs are truncated from 20,000 to 10,000, the first visible line should have a line number of 10,001.
  • Some old JS needs to be removed
  • Haven't tested whether line wrapping is a problem with virtualization yet. If it is then we'll disable line wrapping, like what AzDo does.
  • Selecting text to copy doesn't work well with virtualization. AzDO also has this limitation. Perhaps add a "Raw logs" button to view raw text and people can copy from that. Most console log UIs I've seen offer this kind of feature.
Microsoft Reviewers: Open in CodeFlow

@JamesNK
Copy link
Member Author

JamesNK commented Mar 21, 2024

@tlmii I haven't looked at console logs closely before. Why does the current source code sort log entries and build HTML in the client?

@tlmii
Copy link
Member

tlmii commented Mar 21, 2024

@tlmii I haven't looked at console logs closely before. Why does the current source code sort log entries and build HTML in the client?

Short answer: This was one of the first things we implemented... it started off all in Blazor (sans virtualization - I didn't know about the Virtualize component (not to mention a lot of other Blazor stuff at the time)), someone commented that that'd be too much for Blazor to push to the client as the dataset got larger and we should only send changes to the client manually. So we did. And it hasn't been a priority to fix since then.

await _cancellationSeries.ClearAsync();
if (logEntry.ParentId != null)
{
// If we have a parent id, then we know we're on a non-timestamped line that is part
Copy link
Member

Choose a reason for hiding this comment

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

Was hoping the need to do this interleaving would go away at some point. I guess that some point is not yet...

Copy link
Member Author

@JamesNK JamesNK Mar 21, 2024

Choose a reason for hiding this comment

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

I just replicated what JS was doing. I'm not a fan of it. Reordering data from the server just before it is rendered is probably the wrong place. If reordering is required, it should happen before storing the data inside the host.

I'm thinking about line numbers right now, and this reordering makes it difficult.

Can you talk more about why it is required? What was the original issue?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, sorry, I probably could have been more clear on that comment. I had hoped it was going to go away with streaming logs, but @karolz-ms indicated there were still two separate streams so there might be an issue.

The reordering was required because the logs arrived out of order from the two different streams (stdout and stderr). This was especially true with logs being written to the file system - the first stderr line could have been seconds or minutes after the first stdout line, but since the two files were read at the same time, we'd get them in unpredictable order. Though whatever the source is (docker logs acted slightly differently) they'd still need to be interleaved at some point.

Looking through the current code on the dashboard side, I don't see anywhere obvious where we see the two different streams anymore. Maybe @karolz-ms can speak to how that works in the streaming world now?

Copy link
Member Author

Choose a reason for hiding this comment

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

There are still two streams, they now come from k8s service:

var stdoutStream = await kubernetesService.GetLogStreamAsync(resource, Logs.StreamTypeStdOut, follow: true, timestamps: timestamps, cancellationToken).ConfigureAwait(false);
var stderrStream = await kubernetesService.GetLogStreamAsync(resource, Logs.StreamTypeStdErr, follow: true, timestamps: timestamps, cancellationToken).ConfigureAwait(false);

I think this would still be a problem.

Copy link
Member

Choose a reason for hiding this comment

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

DCP could combine the streams (and apply timestamps to Executable logs), but then we need to figure out how to convey what entries come from stdout vs stderr. E.g. change the format to JSON lines or something similar, but then there is a question of how to deal with non-printable characters etc.

Copy link
Member Author

@JamesNK JamesNK Mar 22, 2024

Choose a reason for hiding this comment

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

If DCP combined the streams, would they be in the correct order? How does DCP get its data? Is it reading from files written to disk, or receiving it more directly?

Copy link
Member Author

@JamesNK JamesNK Mar 22, 2024

Choose a reason for hiding this comment

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

E.g. change the format to JSON lines or something similar, but then there is a question of how to deal with non-printable characters etc.

I guess a JSON serializer would escape them to \uXXXX format.

Copy link
Member

Choose a reason for hiding this comment

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

For Containers the logs arrive in the order the container orchestrator is providing them. But since we are using the CLI to talk to the orchestrator, it boils down to reading stdout and stderr.

The same applies to Executables. When DCP launches Executables directly, it is also responsible for reading stdout and stderr streams. When using the IDE to launch Executables (i.e. dealing with VS projects), it is relying on the IDE to provide the logs.

Bottom line this is probably sufficient for UI to have logs emitted ROUGHLY at the same time to surface close in the combined stream. But there will definitively be some jitter involved, and if the expectation is that developers will be able to infer the order in which things happened based on the order in which they appeared in the (combined) log stream, especially if we are talking about microseconds delay between writes to stdout vs stderr, that is probably a stretch.

@JamesNK JamesNK force-pushed the jamesnk/consolelogs-perf branch from 9a013dd to 980d502 Compare March 22, 2024 01:41
@JamesNK JamesNK requested review from davidfowl and tlmii March 22, 2024 01:48
@JamesNK
Copy link
Member Author

JamesNK commented Mar 22, 2024

@davidfowl I modified the resource logger API to have a struct record to represent line information. It now has a line number on it.

@tlmii
Copy link
Member

tlmii commented Mar 22, 2024

When the page is scrolled to the bottom, there's a bit of a flicker every time the content is updated (the gif doesn't catch all the flickers):

ConsoleLogsFlicker

I switched back to main branch and that doesn't seem to be happening there. Just a function of the way the Virtualize works? I don't think its a blocker since this PR makes the page usable with lots of content which is much more important. But it is kind of annoying when watching the logs come in waiting for something.

@JamesNK
Copy link
Member Author

JamesNK commented Mar 25, 2024

When the page is scrolled to the bottom, there's a bit of a flicker every time the content is updated (the gif doesn't catch all the flickers):

ConsoleLogsFlicker ConsoleLogsFlicker

I switched back to main branch and that doesn't seem to be happening there. Just a function of the way the Virtualize works? I don't think its a blocker since this PR makes the page usable with lots of content which is much more important. But it is kind of annoying when watching the logs come in waiting for something.

I think it's a problem with Virtualize. When new content is added to Virtualize, it adds content to the end, but doesn't move the scroll position with the content. That means new data updates the console and increases the scroll bar size, then our JS sets the scroll position to the end, which then triggers Virtualize to load the end data. There are a bunch of steps instead of new data being loaded once and displayed.

I created an issue about it: dotnet/aspnetcore#54742

I don't think there is a way to improve it (short of copying the source code of Virtualize and changing how it works) right now, but hopefully it can be improved in the next .NET.

cc @SteveSandersonMS @mkArtakMSFT

@JamesNK
Copy link
Member Author

JamesNK commented Mar 26, 2024

Review please 🙏

Copy link
Member

@tlmii tlmii left a comment

Choose a reason for hiding this comment

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

One thing I'm seeing fairly consistently here is that if I launch TestShop, let the Resources page load, go to Console Logs, and choose the dashboard entry from the list, the page doesn't scroll with the logs. It seems like it just stays at wherever it is when the page loads (several pages of logs down from the top, but I guess not all the way at the bottom since it doesn't auto-scroll). Sometimes if I leave the page and come back, it'll act as expected.

That particular log source is the one that is already more than a page of data by the time you get to it and still continues adding logs, so its hard to repro it for other resources.

I think the rest of this looks good other than this and the flicker (which I know is not from our code) so I'll go ahead and approve it. Workaround is easy enough - just use keyboard or mouse to scroll to the bottom.

@JamesNK
Copy link
Member Author

JamesNK commented Mar 26, 2024

I've noticed it not scrolling with new content as the page loads as well. I'll see if I can figure it out.

@JamesNK JamesNK force-pushed the jamesnk/consolelogs-perf branch from e914f4f to 99064dc Compare March 26, 2024 12:45
@JamesNK
Copy link
Member Author

JamesNK commented Mar 26, 2024

I've noticed it not scrolling with new content as the page loads as well. I'll see if I can figure it out.

I've fixed it.

@JamesNK JamesNK merged commit b5c353b into main Mar 26, 2024
8 checks passed
@JamesNK JamesNK deleted the jamesnk/consolelogs-perf branch March 26, 2024 13:36
@JamesNK
Copy link
Member Author

JamesNK commented Mar 26, 2024

/backport to release/8.0-preview5

Copy link
Contributor

Started backporting to release/8.0-preview5: https://github.com/dotnet/aspire/actions/runs/8436937421

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Dashboard console logs - High CPU usage with large amount of logs
3 participants