diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 59e836443..d9ba45df1 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -19,6 +19,7 @@ set(base_SOURCES atomic.hpp atomic-file.cpp atomic-file.hpp base64.cpp base64.hpp + benchmark.hpp boolean.cpp boolean.hpp boolean-script.cpp bulker.hpp configobject.cpp configobject.hpp configobject-ti.hpp configobject-script.cpp diff --git a/lib/base/benchmark.hpp b/lib/base/benchmark.hpp new file mode 100644 index 000000000..e168c5f75 --- /dev/null +++ b/lib/base/benchmark.hpp @@ -0,0 +1,36 @@ +/* Icinga 2 | (c) 2020 Icinga GmbH | GPLv2+ */ + +#ifndef BENCHMARK_H +#define BENCHMARK_H + +#include + +namespace icinga +{ + +/** + * A stopwatch. + * + * @ingroup base + */ +template +class Benchmark final +{ +public: + inline void Start() + { + m_Start = Clock::now(); + } + + inline double Stop() + { + return std::chrono::duration((Clock::now() - m_Start)).count(); + } + +private: + typename Clock::time_point m_Start; +}; + +} + +#endif /* BENCHMARK_H */ diff --git a/lib/cli/consolecommand.cpp b/lib/cli/consolecommand.cpp index 78906bb2a..6de566544 100644 --- a/lib/cli/consolecommand.cpp +++ b/lib/cli/consolecommand.cpp @@ -4,6 +4,7 @@ #include "config/configcompiler.hpp" #include "remote/consolehandler.hpp" #include "remote/url.hpp" +#include "base/benchmark.hpp" #include "base/configwriter.hpp" #include "base/serializer.hpp" #include "base/json.hpp" @@ -31,6 +32,7 @@ #include #include #include +#include #ifdef HAVE_EDITLINE @@ -418,6 +420,7 @@ incomplete: lines[fileName] = command; Value result; + double duration = 0.0; /* Local debug console. */ if (connectAddr.IsEmpty()) { @@ -428,13 +431,21 @@ incomplete: if (!syntaxOnly || dynamic_cast(expr.get())) { if (syntaxOnly) std::cerr << " => " << command << std::endl; - result = Serialize(expr->Evaluate(scriptFrame), 0); + + Benchmark<> benchmark; + benchmark.Start(); + + auto ev (expr->Evaluate(scriptFrame)); + + duration = benchmark.Stop(); + + result = Serialize(std::move(ev), 0); } else result = true; } else { /* Remote debug console. */ try { - result = ExecuteScript(l_Session, command, scriptFrame.Sandboxed); + result = ExecuteScript(l_Session, command, scriptFrame.Sandboxed, duration); } catch (const ScriptError&) { /* Re-throw the exception for the outside try-catch block. */ boost::rethrow_exception(boost::current_exception()); @@ -455,6 +466,7 @@ incomplete: std::cout << ConsoleColorTag(Console_ForegroundCyan); ConfigWriter::EmitValue(std::cout, 1, result); std::cout << ConsoleColorTag(Console_Normal) << "\n"; + std::cout << duration << "s\n"; } else { std::cout << JsonEncode(result) << "\n"; break; @@ -639,7 +651,7 @@ Dictionary::Ptr ConsoleCommand::SendRequest() * @param sandboxed Whether to run this sandboxed. * @return Result value, also contains user errors. */ -Value ConsoleCommand::ExecuteScript(const String& session, const String& command, bool sandboxed) +Value ConsoleCommand::ExecuteScript(const String& session, const String& command, bool sandboxed, double& duration) { /* Extend the url parameters for the request. */ l_Url->SetPath({"v1", "console", "execute-script"}); @@ -661,6 +673,7 @@ Value ConsoleCommand::ExecuteScript(const String& session, const String& command if (resultInfo->Get("code") >= 200 && resultInfo->Get("code") <= 299) { result = resultInfo->Get("result"); + duration = resultInfo->Get("duration"); } else { String errorMessage = resultInfo->Get("status"); diff --git a/lib/cli/consolecommand.hpp b/lib/cli/consolecommand.hpp index 631ec2164..225d9aa8e 100644 --- a/lib/cli/consolecommand.hpp +++ b/lib/cli/consolecommand.hpp @@ -43,7 +43,7 @@ private: static Shared::Ptr Connect(); - static Value ExecuteScript(const String& session, const String& command, bool sandboxed); + static Value ExecuteScript(const String& session, const String& command, bool sandboxed, double& duration); static Array::Ptr AutoCompleteScript(const String& session, const String& command, bool sandboxed); static Dictionary::Ptr SendRequest(); diff --git a/lib/remote/consolehandler.cpp b/lib/remote/consolehandler.cpp index f5a470a9a..1524350ca 100644 --- a/lib/remote/consolehandler.cpp +++ b/lib/remote/consolehandler.cpp @@ -5,6 +5,7 @@ #include "remote/httputility.hpp" #include "remote/filterutility.hpp" #include "config/configcompiler.hpp" +#include "base/benchmark.hpp" #include "base/configtype.hpp" #include "base/configwriter.hpp" #include "base/scriptglobal.hpp" @@ -139,12 +140,18 @@ bool ConsoleHandler::ExecuteScriptHelper(boost::beast::http::request benchmark; + benchmark.Start(); + exprResult = expr->Evaluate(frame); + auto duration (benchmark.Stop()); + resultInfo = new Dictionary({ { "code", 200 }, { "status", "Executed successfully." }, - { "result", Serialize(exprResult, 0) } + { "result", Serialize(exprResult, 0) }, + { "duration", duration } }); } catch (const ScriptError& ex) { DebugInfo di = ex.GetDebugInfo();