From 3acc7dfb9f9ad518acf9b3e8805c199205f64e61 Mon Sep 17 00:00:00 2001 From: sylar-yin <564628276@qq.com> Date: Sun, 21 Jul 2019 23:32:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0ConfigServlet,StatusServlet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: sylar-yin <564628276@qq.com> --- CMakeLists.txt | 2 + sylar/application.cc | 4 + sylar/application.h | 1 + sylar/daemon.cc | 11 ++- sylar/http/http_server.cc | 4 + sylar/http/servlet.cc | 14 +++ sylar/http/servlet.h | 15 +++ sylar/http/servlets/config_servlet.cc | 45 +++++++++ sylar/http/servlets/config_servlet.h | 20 ++++ sylar/http/servlets/status_servlet.cc | 134 +++++++++++++++++++++++++ sylar/http/servlets/status_servlet.h | 20 ++++ sylar/module.cc | 7 +- sylar/sylar.h | 23 +++++ sylar/tcp_server.cc | 14 +++ sylar/tcp_server.h | 2 + sylar/util.cc | 136 +++++++++++++++++++++++++- sylar/util.h | 16 +++ 17 files changed, 464 insertions(+), 4 deletions(-) create mode 100644 sylar/http/servlets/config_servlet.cc create mode 100644 sylar/http/servlets/config_servlet.h create mode 100644 sylar/http/servlets/status_servlet.cc create mode 100644 sylar/http/servlets/status_servlet.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 358f47b..c678026 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,6 +66,8 @@ set(LIB_SRC sylar/http/http_session.cc sylar/http/http_server.cc sylar/http/servlet.cc + sylar/http/servlets/config_servlet.cc + sylar/http/servlets/status_servlet.cc sylar/http/session_data.cc sylar/http/ws_connection.cc sylar/http/ws_session.cc diff --git a/sylar/application.cc b/sylar/application.cc index be0ffa4..8cdd1b2 100644 --- a/sylar/application.cc +++ b/sylar/application.cc @@ -263,4 +263,8 @@ bool Application::getServer(const std::string& type, std::vector return true; } +void Application::listAllServer(std::map >& servers) { + servers = m_servers; +} + } diff --git a/sylar/application.h b/sylar/application.h index a991628..61b56c9 100644 --- a/sylar/application.h +++ b/sylar/application.h @@ -14,6 +14,7 @@ class Application { bool run(); bool getServer(const std::string& type, std::vector& svrs); + void listAllServer(std::map >& servers); private: int main(int argc, char** argv); int run_fiber(); diff --git a/sylar/daemon.cc b/sylar/daemon.cc index 6962dbe..20301dd 100644 --- a/sylar/daemon.cc +++ b/sylar/daemon.cc @@ -25,6 +25,8 @@ std::string ProcessInfo::toString() const { static int real_start(int argc, char** argv, std::function main_cb) { + ProcessInfoMgr::GetInstance()->main_id = getpid(); + ProcessInfoMgr::GetInstance()->main_start_time = time(0); return main_cb(argc, argv); } @@ -50,8 +52,13 @@ static int real_daemon(int argc, char** argv, int status = 0; waitpid(pid, &status, 0); if(status) { - SYLAR_LOG_ERROR(g_logger) << "child crash pid=" << pid - << " status=" << status; + if(status == 9) { + SYLAR_LOG_INFO(g_logger) << "killed"; + break; + } else { + SYLAR_LOG_ERROR(g_logger) << "child crash pid=" << pid + << " status=" << status; + } } else { SYLAR_LOG_INFO(g_logger) << "child finished pid=" << pid; break; diff --git a/sylar/http/http_server.cc b/sylar/http/http_server.cc index 53aa6ae..d60347b 100644 --- a/sylar/http/http_server.cc +++ b/sylar/http/http_server.cc @@ -1,5 +1,7 @@ #include "http_server.h" #include "sylar/log.h" +#include "sylar/http/servlets/config_servlet.h" +#include "sylar/http/servlets/status_servlet.h" namespace sylar { namespace http { @@ -14,6 +16,8 @@ HttpServer::HttpServer(bool keepalive m_dispatch.reset(new ServletDispatch); m_type = "http"; + m_dispatch->addServlet("/_/status", Servlet::ptr(new StatusServlet)); + m_dispatch->addServlet("/_/config", Servlet::ptr(new ConfigServlet)); } void HttpServer::setName(const std::string& v) { diff --git a/sylar/http/servlet.cc b/sylar/http/servlet.cc index 2a4be18..437723d 100644 --- a/sylar/http/servlet.cc +++ b/sylar/http/servlet.cc @@ -128,6 +128,20 @@ Servlet::ptr ServletDispatch::getMatchedServlet(const std::string& uri) { return m_default; } +void ServletDispatch::listAllServletCreator(std::map& infos) { + RWMutexType::ReadLock lock(m_mutex); + for(auto& i : m_datas) { + infos[i.first] = i.second; + } +} + +void ServletDispatch::listAllGlobServletCreator(std::map& infos) { + RWMutexType::ReadLock lock(m_mutex); + for(auto& i : m_globs) { + infos[i.first] = i.second; + } +} + NotFoundServlet::NotFoundServlet(const std::string& name) :Servlet("NotFoundServlet") ,m_name(name) { diff --git a/sylar/http/servlet.h b/sylar/http/servlet.h index a8913e4..c729c2d 100644 --- a/sylar/http/servlet.h +++ b/sylar/http/servlet.h @@ -17,6 +17,7 @@ #include "http.h" #include "http_session.h" #include "sylar/thread.h" +#include "sylar/util.h" namespace sylar { namespace http { @@ -92,6 +93,7 @@ class IServletCreator { typedef std::shared_ptr ptr; virtual ~IServletCreator() {} virtual Servlet::ptr get() const = 0; + virtual std::string getName() const = 0; }; class HoldServletCreator : public IServletCreator { @@ -104,6 +106,10 @@ class HoldServletCreator : public IServletCreator { Servlet::ptr get() const override { return m_servlet; } + + std::string getName() const override { + return m_servlet->getName(); + } private: Servlet::ptr m_servlet; }; @@ -112,11 +118,17 @@ template class ServletCreator : public IServletCreator { public: typedef std::shared_ptr ptr; + ServletCreator() { } + Servlet::ptr get() const override { return Servlet::ptr(new T); } + + std::string getName() const override { + return TypeToName(); + } }; /** @@ -222,6 +234,9 @@ class ServletDispatch : public Servlet { * @return 优先精准匹配,其次模糊匹配,最后返回默认 */ Servlet::ptr getMatchedServlet(const std::string& uri); + + void listAllServletCreator(std::map& infos); + void listAllGlobServletCreator(std::map& infos); private: /// 读写互斥量 RWMutexType m_mutex; diff --git a/sylar/http/servlets/config_servlet.cc b/sylar/http/servlets/config_servlet.cc new file mode 100644 index 0000000..25f37d5 --- /dev/null +++ b/sylar/http/servlets/config_servlet.cc @@ -0,0 +1,45 @@ +#include "config_servlet.h" +#include "sylar/config.h" + +namespace sylar { +namespace http { + +ConfigServlet::ConfigServlet() + :Servlet("ConfigServlet") { +} + +int32_t ConfigServlet::handle(sylar::http::HttpRequest::ptr request + ,sylar::http::HttpResponse::ptr response + ,sylar::http::HttpSession::ptr session) { + std::string type = request->getParam("type"); + if(type == "json") { + response->setHeader("Content-Type", "text/json charset=utf-8"); + } else { + response->setHeader("Content-Type", "text/yaml charset=utf-8"); + } + YAML::Node node; + sylar::Config::Visit([&node](ConfigVarBase::ptr base) { + YAML::Node n; + try { + n = YAML::Load(base->toString()); + } catch(...) { + return; + } + node[base->getName()] = n; + node[base->getName() + "$description"] = base->getDescription(); + }); + if(type == "json") { + Json::Value jvalue; + if(YamlToJson(node, jvalue)) { + response->setBody(JsonUtil::ToString(jvalue)); + return 0; + } + } + std::stringstream ss; + ss << node; + response->setBody(ss.str()); + return 0; +} + +} +} diff --git a/sylar/http/servlets/config_servlet.h b/sylar/http/servlets/config_servlet.h new file mode 100644 index 0000000..0bdf042 --- /dev/null +++ b/sylar/http/servlets/config_servlet.h @@ -0,0 +1,20 @@ +#ifndef __SYLAR_HTTP_SERVLETS_CONFIG_SERVLET_H__ +#define __SYLAR_HTTP_SERVLETS_CONFIG_SERVLET_H__ + +#include "sylar/http/servlet.h" + +namespace sylar { +namespace http { + +class ConfigServlet : public Servlet { +public: + ConfigServlet(); + virtual int32_t handle(sylar::http::HttpRequest::ptr request + , sylar::http::HttpResponse::ptr response + , sylar::http::HttpSession::ptr session) override; +}; + +} +} + +#endif diff --git a/sylar/http/servlets/status_servlet.cc b/sylar/http/servlets/status_servlet.cc new file mode 100644 index 0000000..cbf637a --- /dev/null +++ b/sylar/http/servlets/status_servlet.cc @@ -0,0 +1,134 @@ +#include "status_servlet.h" +#include "sylar/sylar.h" + +namespace sylar { +namespace http { + +StatusServlet::StatusServlet() + :Servlet("StatusServlet") { +} + +std::string format_used_time(int64_t ts) { + std::stringstream ss; + bool v = false; + if(ts >= 3600 * 24) { + ss << (ts / 3600 / 24) << "d "; + ts = ts % (3600 * 24); + v = true; + } + if(ts >= 3600) { + ss << (ts / 3600) << "h "; + ts = ts % 3600; + v = true; + } else if(v) { + ss << "0h "; + } + + if(ts >= 60) { + ss << (ts / 60) << "m "; + ts = ts % 60; + } else if(v) { + ss << "0m "; + } + ss << ts << "s"; + return ss.str(); +} + +int32_t StatusServlet::handle(sylar::http::HttpRequest::ptr request + ,sylar::http::HttpResponse::ptr response + ,sylar::http::HttpSession::ptr session) { + response->setHeader("Content-Type", "text/text; charset=utf-8"); +#define XX(key) \ + ss << std::setw(30) << std::right << key ": " + std::stringstream ss; + ss << "===================================================" << std::endl; + XX("server_version") << "sylar/1.0.0" << std::endl; + + std::vector ms; + ModuleMgr::GetInstance()->listAll(ms); + + XX("modules"); + for(size_t i = 0; i < ms.size(); ++i) { + if(i) { + ss << ";"; + } + ss << ms[i]->getId(); + } + ss << std::endl; + XX("host") << GetHostName() << std::endl; + XX("ipv4") << GetIPv4() << std::endl; + XX("daemon_id") << ProcessInfoMgr::GetInstance()->parent_id << std::endl; + XX("main_id") << ProcessInfoMgr::GetInstance()->main_id << std::endl; + XX("daemon_start") << Time2Str(ProcessInfoMgr::GetInstance()->parent_start_time) << std::endl; + XX("main_start") << Time2Str(ProcessInfoMgr::GetInstance()->main_start_time) << std::endl; + XX("restart_count") << ProcessInfoMgr::GetInstance()->restart_count << std::endl; + XX("daemon_running_time") << format_used_time(time(0) - ProcessInfoMgr::GetInstance()->parent_start_time) << std::endl; + XX("main_running_time") << format_used_time(time(0) - ProcessInfoMgr::GetInstance()->main_start_time) << std::endl; + ss << "===================================================" << std::endl; + XX("fibers") << sylar::Fiber::TotalFibers() << std::endl; + ss << "===================================================" << std::endl; + ss << "" << std::endl; + ss << sylar::LoggerMgr::GetInstance()->toYamlString() << std::endl; + ss << "===================================================" << std::endl; + ss << "" << std::endl; + sylar::WorkerMgr::GetInstance()->dump(ss) << std::endl; + + std::map > servers; + sylar::Application::GetInstance()->listAllServer(servers); + ss << "===================================================" << std::endl; + for(auto it = servers.begin(); + it != servers.end(); ++it) { + if(it != servers.begin()) { + ss << "***************************************************" << std::endl; + } + ss << "first << ">" << std::endl; + sylar::http::HttpServer::ptr hs; + for(auto iit = it->second.begin(); + iit != it->second.end(); ++iit) { + if(iit != it->second.begin()) { + ss << "---------------------------------------------------" << std::endl; + } + if(!hs) { + hs = std::dynamic_pointer_cast(*iit); + } + ss << (*iit)->toString() << std::endl; + } + if(hs) { + auto sd = hs->getServletDispatch(); + if(sd) { + std::map infos; + sd->listAllServletCreator(infos); + if(!infos.empty()) { + ss << "[Servlets]" << std::endl; +#define XX2(key) \ + ss << std::setw(30) << std::right << key << ": " + for(auto& i : infos) { + XX2(i.first) << i.second->getName() << std::endl; + } + infos.clear(); + } + sd->listAllGlobServletCreator(infos); + if(!infos.empty()) { + ss << "[Servlets.Globs]" << std::endl; + for(auto& i : infos) { + XX2(i.first) << i.second->getName() << std::endl; + } + infos.clear(); + } + } + } + } + ss << "===================================================" << std::endl; + for(size_t i = 0; i < ms.size(); ++i) { + if(i) { + ss << "***************************************************" << std::endl; + } + ss << ms[i]->statusString() << std::endl; + } + + response->setBody(ss.str()); + return 0; +} + +} +} diff --git a/sylar/http/servlets/status_servlet.h b/sylar/http/servlets/status_servlet.h new file mode 100644 index 0000000..f29adac --- /dev/null +++ b/sylar/http/servlets/status_servlet.h @@ -0,0 +1,20 @@ +#ifndef __SYLAR_HTTP_SERVLETS_STATUS_SERVLET_H__ +#define __SYLAR_HTTP_SERVLETS_STATUS_SERVLET_H__ + +#include "sylar/http/servlet.h" + +namespace sylar { +namespace http { + +class StatusServlet : public Servlet { +public: + StatusServlet(); + virtual int32_t handle(sylar::http::HttpRequest::ptr request + , sylar::http::HttpResponse::ptr response + , sylar::http::HttpSession::ptr session) override; +}; + +} +} + +#endif diff --git a/sylar/module.cc b/sylar/module.cc index 581892d..d286cc0 100644 --- a/sylar/module.cc +++ b/sylar/module.cc @@ -69,7 +69,12 @@ bool Module::onServerUp() { } std::string Module::statusString() { - return ""; + std::stringstream ss; + ss << "Module name=" << getName() + << " version=" << getVersion() + << " filename=" << getFilename() + << std::endl; + return ss.str(); } RockModule::RockModule(const std::string& name diff --git a/sylar/sylar.h b/sylar/sylar.h index 2cc34da..a73f006 100644 --- a/sylar/sylar.h +++ b/sylar/sylar.h @@ -26,6 +26,7 @@ #include "module.h" #include "mutex.h" #include "noncopyable.h" +#include "protocol.h" #include "scheduler.h" #include "singleton.h" #include "socket.h" @@ -37,6 +38,18 @@ #include "util.h" #include "worker.h" +#include "db/db.h" +#include "db/mysql.h" +#include "db/sqlite3.h" + +#include "ds/cache_status.h" +#include "ds/lru_cache.h" +#include "ds/timed_cache.h" +#include "ds/timed_lru_cache.h" + +#include "email/email.h" +#include "email/smtp.h" + #include "http/http.h" #include "http/http11_common.h" #include "http/http11_parser.h" @@ -46,13 +59,23 @@ #include "http/http_session.h" #include "http/httpclient_parser.h" #include "http/servlet.h" +#include "http/session_data.h" #include "http/ws_connection.h" #include "http/ws_server.h" #include "http/ws_servlet.h" #include "http/ws_session.h" +#include "rock/rock_protocol.h" +#include "rock/rock_server.h" +#include "rock/rock_stream.h" + +#include "streams/async_socket_stream.h" +#include "streams/load_balance.h" #include "streams/socket_stream.h" +#include "streams/zlib_stream.h" +#include "util/crypto_util.h" #include "util/hash_util.h" +#include "util/json_util.h" #endif diff --git a/sylar/tcp_server.cc b/sylar/tcp_server.cc index 24eba95..5acc281 100644 --- a/sylar/tcp_server.cc +++ b/sylar/tcp_server.cc @@ -128,4 +128,18 @@ bool TcpServer::loadCertificates(const std::string& cert_file, const std::string return true; } +std::string TcpServer::toString(const std::string& prefix) { + std::stringstream ss; + ss << prefix << "[type=" << m_type + << " name=" << m_name << " ssl=" << m_ssl + << " worker=" << (m_worker ? m_worker->getName() : "") + << " accept=" << (m_acceptWorker ? m_acceptWorker->getName() : "") + << " recv_timeout=" << m_recvTimeout << "]" << std::endl; + std::string pfx = prefix.empty() ? " " : prefix; + for(auto& i : m_socks) { + ss << pfx << pfx << *i << std::endl; + } + return ss.str(); +} + } diff --git a/sylar/tcp_server.h b/sylar/tcp_server.h index d0b92bd..736c5c3 100644 --- a/sylar/tcp_server.h +++ b/sylar/tcp_server.h @@ -187,6 +187,8 @@ class TcpServer : public std::enable_shared_from_this TcpServerConf::ptr getConf() const { return m_conf;} void setConf(TcpServerConf::ptr v) { m_conf = v;} void setConf(const TcpServerConf& v); + + virtual std::string toString(const std::string& prefix = ""); protected: /** diff --git a/sylar/util.cc b/sylar/util.cc index dc73c6e..6029b8c 100644 --- a/sylar/util.cc +++ b/sylar/util.cc @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include "log.h" #include "fiber.h" @@ -22,6 +24,25 @@ uint32_t GetFiberId() { return sylar::Fiber::GetFiberId(); } +static std::string demangle(const char* str) { + size_t size = 0; + int status = 0; + std::string rt; + rt.resize(256); + if(1 == sscanf(str, "%*[^(]%*[^_]%255[^)+]", &rt[0])) { + char* v = abi::__cxa_demangle(&rt[0], nullptr, &size, &status); + if(v) { + std::string result(v); + free(v); + return result; + } + } + if(1 == sscanf(str, "%255s", &rt[0])) { + return rt; + } + return str; +} + void Backtrace(std::vector& bt, int size, int skip) { void** array = (void**)malloc((sizeof(void*) * size)); size_t s = ::backtrace(array, size); @@ -33,7 +54,7 @@ void Backtrace(std::vector& bt, int size, int skip) { } for(size_t i = skip; i < s; ++i) { - bt.push_back(strings[i]); + bt.push_back(demangle(strings[i])); } free(strings); @@ -517,6 +538,119 @@ std::wstring StringUtil::StringToWString(const std::string& s) { return wstr_result; } +std::string GetHostName() { + std::shared_ptr host(new char[512], sylar::delete_array); + memset(host.get(), 0, 512); + gethostname(host.get(), 511); + return host.get(); +} + +in_addr_t GetIPv4Inet() { + struct ifaddrs* ifas = nullptr; + struct ifaddrs* ifa = nullptr; + + in_addr_t localhost = inet_addr("127.0.0.1"); + if(getifaddrs(&ifas)) { + SYLAR_LOG_ERROR(g_logger) << "getifaddrs errno=" << errno + << " errstr=" << strerror(errno); + return localhost; + } + + in_addr_t ipv4 = localhost; + + for(ifa = ifas; ifa && ifa->ifa_addr; ifa = ifa->ifa_next) { + if(ifa->ifa_addr->sa_family != AF_INET) { + continue; + } + if(!strncasecmp(ifa->ifa_name, "lo", 2)) { + continue; + } + ipv4 = ((struct sockaddr_in*)ifa->ifa_addr)->sin_addr.s_addr; + if(ipv4 == localhost) { + continue; + } + } + if(ifas != nullptr) { + freeifaddrs(ifas); + } + return ipv4; +} + +std::string _GetIPv4() { + std::shared_ptr ipv4(new char[INET_ADDRSTRLEN], sylar::delete_array); + memset(ipv4.get(), 0, INET_ADDRSTRLEN); + auto ia = GetIPv4Inet(); + inet_ntop(AF_INET, &ia, ipv4.get(), INET_ADDRSTRLEN); + return ipv4.get(); +} +std::string GetIPv4() { + static const std::string ip = _GetIPv4(); + return ip; +} + +bool YamlToJson(const YAML::Node& ynode, Json::Value& jnode) { + try { + if(ynode.IsScalar()) { + Json::Value v(ynode.Scalar()); + jnode.swapPayload(v); + return true; + } + if(ynode.IsSequence()) { + for(size_t i = 0; i < ynode.size(); ++i) { + Json::Value v; + if(YamlToJson(ynode[i], v)) { + jnode.append(v); + } else { + return false; + } + } + } else if(ynode.IsMap()) { + for(auto it = ynode.begin(); + it != ynode.end(); ++it) { + Json::Value v; + if(YamlToJson(it->second, v)) { + jnode[it->first.Scalar()] = v; + } else { + return false; + } + } + } + } catch(...) { + return false; + } + return true; +} + +bool JsonToYaml(const Json::Value& jnode, YAML::Node& ynode) { + try { + if(jnode.isArray()) { + for(int i = 0; i < (int)jnode.size(); ++i) { + YAML::Node n; + if(JsonToYaml(jnode[i], n)) { + ynode.push_back(n); + } else { + return false; + } + } + } else if(jnode.isObject()) { + for(auto it = jnode.begin(); + it != jnode.end(); + ++it) { + YAML::Node n; + if(JsonToYaml(*it, n)) { + ynode[it.name()] = n; + } else { + return false; + } + } + } else { + ynode = jnode.asString(); + } + } catch (...) { + return false; + } + return true; +} } diff --git a/sylar/util.h b/sylar/util.h index c88a813..87438bc 100644 --- a/sylar/util.h +++ b/sylar/util.h @@ -9,6 +9,7 @@ #ifndef __SYLAR_UTIL_H__ #define __SYLAR_UTIL_H__ +#include #include #include #include @@ -18,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include "sylar/util/hash_util.h" #include "sylar/util/json_util.h" @@ -226,6 +230,18 @@ class StringUtil { }; +std::string GetHostName(); +std::string GetIPv4(); + +bool YamlToJson(const YAML::Node& ynode, Json::Value& jnode); +bool JsonToYaml(const Json::Value& jnode, YAML::Node& ynode); + +template +const char* TypeToName() { + static const char* s_name = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, nullptr); + return s_name; +} + } #endif