static void print_help()
{
- fprintf(stderr,
+ fprintf(stdout,
".NET Core debugger for Linux/macOS.\n"
"\n"
"Options:\n"
"--attach <process-id> Attach the debugger to the specified process id.\n"
"--interpreter=mi Puts the debugger into MI mode.\n"
- "--interpreter=vscode Puts the debugger into VS Code Debugger mode.\n");
+ "--interpreter=vscode Puts the debugger into VS Code Debugger mode.\n"
+ "--engineLogging[=<path to log file>] Enable logging to VsDbg-UI or file for the engine.\n"
+ " Only supported by the VsCode interpreter.\n"
+ );
}
int main(int argc, char *argv[])
InterpreterVSCode
} interpreterType = InterpreterMI;
+ bool engineLogging = false;
+ std::string logFilePath;
+
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], "--attach") == 0)
interpreterType = InterpreterVSCode;
continue;
}
+ else if (strcmp(argv[i], "--engineLogging") == 0)
+ {
+ engineLogging = true;
+ continue;
+ }
+ else if (strstr(argv[i], "--engineLogging=") == argv[i])
+ {
+ engineLogging = true;
+ logFilePath = argv[i] + strlen("--engineLogging=");
+ continue;
+ }
else if (strcmp(argv[i], "--help") == 0)
{
print_help();
switch(interpreterType)
{
case InterpreterMI:
+ if (engineLogging)
+ {
+ fprintf(stderr, "Error: Engine logging is only supported in VsCode interpreter mode.\n");
+ return EXIT_FAILURE;
+ }
protocol.reset(new MIProtocol());
static_cast<MIProtocol*>(protocol.get())->SetDebugger(&debugger);
break;
case InterpreterVSCode:
- protocol.reset(new VSCodeProtocol());
- static_cast<VSCodeProtocol*>(protocol.get())->SetDebugger(&debugger);
+ {
+ VSCodeProtocol *vsCodeProtocol = new VSCodeProtocol();
+ protocol.reset(vsCodeProtocol);
+ vsCodeProtocol->SetDebugger(&debugger);
+ if (engineLogging)
+ vsCodeProtocol->EngineLogging(logFilePath);
break;
+ }
}
debugger.SetProtocol(protocol.get());
std::string output = response.dump();
std::cout << CONTENT_LENGTH << output.size() << TWO_CRLF << output;
std::cout.flush();
+ Log(lock, LOG_EVENT, output);
}
typedef std::function<HRESULT(
if (requestText.empty())
break;
+ Log(std::lock_guard<std::mutex>(m_outMutex), LOG_COMMAND, requestText);
+
json request = json::parse(requestText);
std::string command = request.at("command");
std::string output = response.dump();
std::cout << CONTENT_LENGTH << output.size() << TWO_CRLF << output;
std::cout.flush();
+ Log(lock, LOG_RESPONSE, output);
}
}
m_debugger->Disconnect();
}
+
+const std::string VSCodeProtocol::LOG_COMMAND("-> (C) ");
+const std::string VSCodeProtocol::LOG_RESPONSE("<- (R) ");
+const std::string VSCodeProtocol::LOG_EVENT("<- (E) ");
+
+void VSCodeProtocol::EngineLogging(const std::string &path)
+{
+ if (path.empty())
+ {
+ m_engineLogOutput = LogConsole;
+ }
+ else
+ {
+ m_engineLogOutput = LogFile;
+ m_engineLog.open(path);
+ }
+}
+
+void VSCodeProtocol::Log(const std::lock_guard<std::mutex> &lock, const std::string &prefix, const std::string &text)
+{
+ switch(m_engineLogOutput)
+ {
+ case LogNone:
+ return;
+ case LogFile:
+ m_engineLog << prefix << text << std::endl;
+ m_engineLog.flush();
+ return;
+ case LogConsole:
+ {
+ json response;
+ response["seq"] = m_seqCounter++;
+ response["type"] = "event";
+ response["event"] = "output";
+ response["body"] = json{
+ {"category", "console"},
+ {"output", prefix + text + "\n"}
+ };
+ std::string output = response.dump();
+ std::cout << CONTENT_LENGTH << output.size() << TWO_CRLF << output;
+ std::cout.flush();
+ return;
+ }
+ }
+}
// See the LICENSE file in the project root for more information.
#include <mutex>
+#include <fstream>
#include "json.hpp"
#include "debugger.h"
static const std::string TWO_CRLF;
static const std::string CONTENT_LENGTH;
+ static const std::string LOG_COMMAND;
+ static const std::string LOG_RESPONSE;
+ static const std::string LOG_EVENT;
+
std::mutex m_outMutex;
+ enum {
+ LogNone,
+ LogConsole,
+ LogFile
+ } m_engineLogOutput;
+ std::ofstream m_engineLog;
bool m_exit;
Debugger *m_debugger;
void EmitEvent(const std::string &name, const nlohmann::json &body);
HRESULT HandleCommand(const std::string &command, const nlohmann::json &arguments, nlohmann::json &body);
+
+ void Log(const std::lock_guard<std::mutex> &lock, const std::string &prefix, const std::string &text);
+
public:
- VSCodeProtocol() : m_exit(false), m_seqCounter(1) {}
+ VSCodeProtocol() : m_engineLogOutput(LogNone), m_exit(false), m_seqCounter(1) {}
void SetDebugger(Debugger *debugger) { m_debugger = debugger; }
+ void EngineLogging(const std::string &path);
+
void EmitInitializedEvent() override;
void EmitStoppedEvent(StoppedEvent event) override;
void EmitExitedEvent(ExitedEvent event) override;