1 // SPDX-License-Identifier: Apache-2.0 2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3 4 #include "webserver_cli.hpp" 5 6 #include "boost_formatters.hpp" 7 #include "logging.hpp" 8 #include "webserver_run.hpp" 9 10 #include <CLI/CLI.hpp> 11 #include <boost/asio/io_context.hpp> 12 #include <sdbusplus/asio/connection.hpp> 13 14 #include <algorithm> 15 #include <array> 16 #include <cctype> 17 #include <memory> 18 #include <string> 19 20 // Override default log option: 21 static void cliLogLevel(const std::string& logLevel) 22 { 23 crow::getBmcwebCurrentLoggingLevel() = crow::getLogLevelFromName(logLevel); 24 } 25 26 static constexpr std::array<std::string, 7> levels{ 27 "DISABLED", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "ENABLED"}; 28 29 // Check if debug level is valid 30 static std::string validateLogLevel(std::string& input) 31 { 32 std::transform(input.begin(), input.end(), input.begin(), ::toupper); 33 const std::string* iter = std::ranges::find(levels, input); 34 if (iter == levels.end()) 35 { 36 return {"Invalid log level"}; 37 } 38 return {}; 39 } 40 41 static std::string helpMsg() 42 { 43 std::string help = "\nLog levels to choose from:\n"; 44 for (const std::string& prompt : levels) 45 { 46 std::string level = prompt; 47 std::transform(level.begin(), level.end(), level.begin(), ::tolower); 48 help.append(level + "\n"); 49 } 50 return help; 51 } 52 53 static int setLogLevel(std::string& loglevel) 54 { 55 // Define sdbus interfaces: 56 std::string service = "xyz.openbmc_project.bmcweb"; 57 std::string path = "/xyz/openbmc_project/bmcweb"; 58 std::string iface = "xyz.openbmc_project.bmcweb"; 59 std::string method = "SetLogLevel"; 60 61 std::transform(loglevel.begin(), loglevel.end(), loglevel.begin(), 62 ::toupper); 63 // Set up dbus connection: 64 boost::asio::io_context io; 65 auto conn = std::make_shared<sdbusplus::asio::connection>(io); 66 67 // Attempt to async_call to set logging level 68 conn->async_method_call( 69 [&io, loglevel](boost::system::error_code& ec) mutable { 70 if (ec) 71 { 72 BMCWEB_LOG_ERROR("SetLogLevel returned error with {}", ec); 73 } 74 else 75 { 76 BMCWEB_LOG_INFO("logging level changed to: {}", loglevel); 77 } 78 io.stop(); 79 }, 80 service, path, iface, method, loglevel); 81 82 io.run(); 83 84 return 0; 85 } 86 87 int runCLI(int argc, char** argv) noexcept(false) 88 { 89 CLI::App app("BMCWeb CLI"); 90 91 const CLI::Validator levelValidator = 92 CLI::Validator(validateLogLevel, "valid level"); 93 94 CLI::App* loglevelsub = 95 app.add_subcommand("loglevel", "Set bmcweb log level"); 96 97 std::string loglevel; 98 loglevelsub->add_option("level", loglevel, helpMsg()) 99 ->required() 100 ->check(levelValidator); 101 102 CLI::App* daemon = app.add_subcommand("daemon", "Run webserver"); 103 104 CLI11_PARSE(app, argc, argv) 105 106 if (loglevelsub->parsed()) 107 { 108 cliLogLevel("INFO"); 109 return setLogLevel(loglevel); 110 } 111 if (daemon->parsed()) 112 { 113 return runWebserver(); 114 } 115 runWebserver(); 116 117 return 0; 118 } 119