Skip to content
Open
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
45 changes: 44 additions & 1 deletion localization/strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -1871,4 +1871,47 @@ You can also access more VS Code Remote options through the command palette with
<data name="Settings_VMIdleTimeoutTextBox.AutomationProperties.HelpText" xml:space="preserve">
<value>The number of milliseconds that a VM is idle, before it is shut down.</value>
</data>
</root>
<data name="MessageWsladiagUsage" xml:space="preserve">
<value>wsladiag - WSLA diagnostics tool
Usage:
wsladiag list
wsladiag shell &lt;SessionName&gt; [--verbose]
wsladiag --help</value>
<comment>{Locked="--verbose]"}{Locked="--help"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageWslaSessionNotFound" xml:space="preserve">
<value>Session not found: '{}'</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageWslaOpenSessionFailed" xml:space="preserve">
<value>OpenSessionByName('{}') failed</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageWslaNoSessionsFound" xml:space="preserve">
<value>No WSLA sessions found.</value>
</data>
<data name="MessageWslaSessionsFound" xml:space="preserve">
<value>Found {} WSLA session(s):</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageWslaShellExited" xml:space="preserve">
<value>{} exited with: {}</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
<data name="MessageWslaShellSignalled" xml:space="preserve">
<value> (signalled)</value>
</data>
<data name="MessageWslaHeaderId" xml:space="preserve">
<value>ID</value>
</data>
<data name="MessageWslaHeaderCreatorPid" xml:space="preserve">
<value>Creator PID</value>
</data>
<data name="MessageWslaHeaderDisplayName" xml:space="preserve">
<value>Display Name</value>
</data>
<data name="MessageWslaUnknownCommand" xml:space="preserve">
<value>Unknown command: '{}'</value>
<comment>{FixedPlaceholder="{}"}Command line arguments, file names and string inserts should not be translated</comment>
</data>
</root>
75 changes: 56 additions & 19 deletions src/windows/wsladiag/wsladiag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,23 @@ Module Name:

using namespace wsl::shared;
namespace wslutil = wsl::windows::common::wslutil;
using wsl::shared::Localization;
using wsl::windows::common::Context;
using wsl::windows::common::ExecutionContext;
using wsl::windows::common::WSLAProcessLauncher;

// Adding a helper to factor error handling between all the arguments.
static int ReportError(const std::wstring& context, HRESULT hr)
{
const std::wstring hrMessage = wslutil::ErrorCodeToString(hr);
const std::wstring hrMessage = wslutil::GetErrorString(hr);

if (!hrMessage.empty())
{
wslutil::PrintMessage(std::format(L"{}: 0x{:08x} - {}", context, static_cast<unsigned int>(hr), hrMessage), stderr);
wslutil::PrintMessage(std::format(L"{}: 0x{:08x} - {}", context, static_cast<uint32_t>(hr), hrMessage), stderr);
}
else
{
wslutil::PrintMessage(std::format(L"{}: 0x{:08x}", context, static_cast<unsigned int>(hr)), stderr);
wslutil::PrintMessage(std::format(L"{}: 0x{:08x}", context, static_cast<uint32_t>(hr)), stderr);
}

return 1;
Expand Down Expand Up @@ -64,11 +67,11 @@ static int RunShellCommand(const std::wstring& sessionName, bool verbose)
{
if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND))
{
wslutil::PrintMessage(std::format(L"Session not found: '{}'", sessionName), stderr);
wslutil::PrintMessage(Localization::MessageWslaSessionNotFound(sessionName.c_str()), stderr);
return 1;
}

return ReportError(std::format(L"OpenSessionByName('{}') failed", sessionName), hr);
return ReportError(Localization::MessageWslaOpenSessionFailed(sessionName.c_str()), hr);
}

log(L"[diag] OpenSessionByName succeeded");
Expand Down Expand Up @@ -179,10 +182,17 @@ static int RunShellCommand(const std::wstring& sessionName, bool verbose)
wsl::windows::common::relay::InterruptableRelay(ttyOut.get(), consoleOut, exitEvent.get());

process.GetExitEvent().wait();
auto [code, signalled] = process.GetExitState();
auto [exitCode, signalled] = process.GetExitState();

std::wstring shellWide(shell.begin(), shell.end());
wslutil::PrintMessage(std::format(L"{} exited with: {}{}", shellWide, code, signalled ? L" (signalled)" : L""), stdout);
std::wstring message = Localization::MessageWslaShellExited(shellWide.c_str(), exitCode);

if (signalled)
{
message += Localization::MessageWslaShellSignalled();
}

wslutil::PrintMessage(message, stdout);

return 0;
}
Expand All @@ -198,48 +208,74 @@ static int RunListCommand(bool /*verbose*/)

if (sessions.size() == 0)
{
wslutil::PrintMessage(L"No WSLA sessions found.", stdout);
wslutil::PrintMessage(Localization::MessageWslaNoSessionsFound(), stdout);
return 0;
}

wslutil::PrintMessage(std::format(L"Found {} WSLA session{}:", sessions.size(), sessions.size() > 1 ? L"s" : L""), stdout);
wslutil::PrintMessage(Localization::MessageWslaSessionsFound(sessions.size()), stdout);
// Compute column widths from headers + data.
const auto idHeader = Localization::MessageWslaHeaderId();
const auto pidHeader = Localization::MessageWslaHeaderCreatorPid();
const auto nameHeader = Localization::MessageWslaHeaderDisplayName();

// Compute column widths from headers + data (same pattern as wsl --list).
size_t idWidth = wcslen(L"ID");
size_t pidWidth = wcslen(L"Creator PID");
size_t idWidth = idHeader.size();
size_t pidWidth = pidHeader.size();
size_t nameWidth = nameHeader.size();

for (const auto& s : sessions)
{
idWidth = std::max(idWidth, std::to_wstring(s.SessionId).size());
pidWidth = std::max(pidWidth, std::to_wstring(s.CreatorPid).size());
nameWidth = std::max(nameWidth, static_cast<size_t>(s.DisplayName ? wcslen(s.DisplayName) : 0));
}

// Header
wprintf(L"%-*ls %-*ls %ls\n", static_cast<int>(idWidth), L"ID", static_cast<int>(pidWidth), L"Creator PID", L"Display Name");
wprintf(
L"%-*ls %-*ls %-*ls\n",
static_cast<int>(idWidth),
idHeader.c_str(),
static_cast<int>(pidWidth),
pidHeader.c_str(),
static_cast<int>(nameWidth),
nameHeader.c_str());

// Underline
std::wstring idDash(idWidth, L'-');
std::wstring pidDash(pidWidth, L'-');
std::wstring nameDash(wcslen(L"Display Name"), L'-');
std::wstring nameDash(nameWidth, L'-');

wprintf(
L"%-*ls %-*ls %ls\n", static_cast<int>(idWidth), idDash.c_str(), static_cast<int>(pidWidth), pidDash.c_str(), nameDash.c_str());
L"%-*ls %-*ls %-*ls\n",
static_cast<int>(idWidth),
idDash.c_str(),
static_cast<int>(pidWidth),
pidDash.c_str(),
static_cast<int>(nameWidth),
nameDash.c_str());

// Rows
for (const auto& s : sessions)
{
const wchar_t* displayName = s.DisplayName ? s.DisplayName : L"";

wprintf(
L"%-*lu %-*lu %ls\n",
L"%-*lu %-*lu %-*ls\n",
static_cast<int>(idWidth),
static_cast<unsigned long>(s.SessionId),
static_cast<int>(pidWidth),
static_cast<unsigned long>(s.CreatorPid),
s.DisplayName);
static_cast<int>(nameWidth),
displayName);
}

return 0;
}

static void PrintUsage()
{
wslutil::PrintMessage(Localization::MessageWsladiagUsage(), stderr);
}

int wsladiag_main(std::wstring_view commandLine)
{
wslutil::ConfigureCrt();
Expand Down Expand Up @@ -314,8 +350,9 @@ int wsladiag_main(std::wstring_view commandLine)
}
else
{
wslutil::PrintMessage(std::format(L"Unknown command: '{}'", verb), stderr);
printUsage();
wslutil::PrintMessage(Localization::MessageWslaUnknownCommand(verb.c_str()), stderr);
PrintUsage();

return 1;
}
}
Expand Down