muduo_inspect库源码分析(41)

来源:互联网 发布:设计院改制 知乎 编辑:程序博客网 时间:2024/04/28 00:00

muduo_inspect库通过HTTP方式为服务器提供监控接口
接受了多少个TCP连接
当前有多少个活动连接
一共响应了多少次请求
每次请求的平均响应时间多少毫秒
。。。

Inspector     // 包含了一个HttpServer对象
ProcessInspector // 通过ProcessInfo返回进程信息

ProcessInfo // 获取进程相关信息





ProcessInspectort头文件

ProcessInspector.h

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is an internal header file, you should not include this.#ifndef MUDUO_NET_INSPECT_PROCESSINSPECTOR_H#define MUDUO_NET_INSPECT_PROCESSINSPECTOR_H#include <muduo/net/inspect/Inspector.h>#include <boost/noncopyable.hpp>namespace muduo{namespace net{class ProcessInspector : boost::noncopyable{ public:  void registerCommands(Inspector* ins);    // 注册命令接口 private:  static string pid(HttpRequest::Method, const Inspector::ArgList&);  static string procStatus(HttpRequest::Method, const Inspector::ArgList&);  static string openedFiles(HttpRequest::Method, const Inspector::ArgList&);  static string threads(HttpRequest::Method, const Inspector::ArgList&);};}}#endif  // MUDUO_NET_INSPECT_PROCESSINSPECTOR_H




ProcessInspectort源文件

ProcessInspector.cc


// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//#include <muduo/net/inspect/ProcessInspector.h>#include <muduo/base/ProcessInfo.h>#include <stdio.h>using namespace muduo;using namespace muduo::net;/*命令注册*/void ProcessInspector::registerCommands(Inspector* ins){  /*muduo             :   proc    command           :   pid    commandCallback   :   pid    commnadHelp       :   print id  */  ins->add("proc", "pid", ProcessInspector::pid, "print pid");  ins->add("proc", "status", ProcessInspector::procStatus, "print /proc/self/status");  ins->add("proc", "opened_files", ProcessInspector::openedFiles, "count /proc/self/fd");  ins->add("proc", "threads", ProcessInspector::threads, "list /proc/self/task");}string ProcessInspector::pid(HttpRequest::Method, const Inspector::ArgList&){  char buf[32];  snprintf(buf, sizeof buf, "%d", ProcessInfo::pid());  return buf;}string ProcessInspector::procStatus(HttpRequest::Method, const Inspector::ArgList&){  return ProcessInfo::procStatus();}string ProcessInspector::openedFiles(HttpRequest::Method, const Inspector::ArgList&){  char buf[32];  snprintf(buf, sizeof buf, "%d", ProcessInfo::openedFiles());  return buf;}string ProcessInspector::threads(HttpRequest::Method, const Inspector::ArgList&){  std::vector<pid_t> threads = ProcessInfo::threads();  string result;  for (size_t i = 0; i < threads.size(); ++i)  {    char buf[32];    snprintf(buf, sizeof buf, "%d\n", threads[i]);    result += buf;  }  return result;}





Inspector头文件

Inspector.h

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is a public header file, it must only include public header files.#ifndef MUDUO_NET_INSPECT_INSPECTOR_H#define MUDUO_NET_INSPECT_INSPECTOR_H#include <muduo/base/Mutex.h>#include <muduo/net/http/HttpRequest.h>#include <muduo/net/http/HttpServer.h>#include <map>#include <boost/function.hpp>#include <boost/noncopyable.hpp>#include <boost/scoped_ptr.hpp>namespace muduo{namespace net{class ProcessInspector;// A internal inspector of the running process, usually a singleton.class Inspector : boost::noncopyable{ public:  typedef std::vector<string> ArgList;  typedef boost::function<string (HttpRequest::Method, const ArgList& args)> Callback;  Inspector(EventLoop* loop,            const InetAddress& httpAddr,            const string& name);  ~Inspector();  // 如add("proc", "pid", ProcessInspector::pid, "print pid");  // http://192.168.159.188:12345/proc/pid这个http请求就会相应的调用ProcessInspector::pid来处理  void add(const string& module,           const string& command,           const Callback& cb,           const string& help); private:  typedef std::map<string, Callback> CommandList;  typedef std::map<string, string> HelpList;  void start();  void onRequest(const HttpRequest& req, HttpResponse* resp);  HttpServer server_;  boost::scoped_ptr<ProcessInspector> processInspector_;  MutexLock mutex_;  std::map<string, CommandList> commands_;  std::map<string, HelpList> helps_;  /*commands_ --- > <muduo commandlist>helps_    ----> <muduo helplist>commandlist---> <command callback>HelpList  ----> <command helplist>commands_[][]=xxhelps_[][]=xxx   */};}}#endif  // MUDUO_NET_INSPECT_INSPECTOR_H




Inspector源文件

Inspector.cc

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//#include <muduo/net/inspect/Inspector.h>#include <muduo/base/Thread.h>#include <muduo/net/EventLoop.h>#include <muduo/net/http/HttpRequest.h>#include <muduo/net/http/HttpResponse.h>#include <muduo/net/inspect/ProcessInspector.h>//#include <iostream>//#include <iterator>//#include <sstream>#include <boost/bind.hpp>#include <boost/algorithm/string/classification.hpp>#include <boost/algorithm/string/split.hpp>using namespace muduo;using namespace muduo::net;namespace{Inspector* g_globalInspector = 0;// Looks buggystd::vector<string> split(const string& str){  std::vector<string> result;  size_t start = 0;  size_t pos = str.find('/');  while (pos != string::npos)  {    if (pos > start)    {      result.push_back(str.substr(start, pos-start));    }    start = pos+1;    pos = str.find('/', start);  }  if (start < str.length())      // 说明最后一个字符不是'/'  {    result.push_back(str.substr(start));  }  return result;}}Inspector::Inspector(EventLoop* loop,                     const InetAddress& httpAddr,                     const string& name)    : server_(loop, httpAddr, "Inspector:"+name),      processInspector_(new ProcessInspector){  //断言在主线程当中  assert(CurrentThread::isMainThread());  assert(g_globalInspector == 0);  g_globalInspector = this;  /*设置请求的回调函数,这里的请求是完成了协议的解析之后*/  server_.setHttpCallback(boost::bind(&Inspector::onRequest, this, _1, _2));  /*注册命令*/  processInspector_->registerCommands(this);  // 这样子做法是为了防止竞态问题  // 如果直接调用start,(当前线程不是loop所属的IO线程,是主线程)那么有可能,当前构造函数还没返回,  // HttpServer所在的IO线程可能已经收到了http客户端的请求了(因为这时候HttpServer已启动),那么就会回调  // Inspector::onRequest,而这时候构造函数还没返回,也就是说对象还没完全构造好。那么就会出现问题了  loop->runAfter(0, boost::bind(&Inspector::start, this)); // little race condition}Inspector::~Inspector(){  assert(CurrentThread::isMainThread());  g_globalInspector = NULL;}void Inspector::add(const string& module,                    const string& command,                    const Callback& cb,                    const string& help){  /*这里要不要加锁??因为在构造函数时 程序是注册完 processInspector_->registerCommands(this); 才执行loop->runAfter(0, boost::bind(&Inspector::start, this)); // little race condition。如果程序进行扩充时,就要了。class TcpInspector : boost::noncopyable{ public:  void registerCommands(Inspector* ins);  // 注册命令接口 private:  static string pid(HttpRequest::Method, const Inspector::ArgList&);  static string procStatus(HttpRequest::Method, const Inspector::ArgList&);  static string openedFiles(HttpRequest::Method, const Inspector::ArgList&);  static string threads(HttpRequest::Method, const Inspector::ArgList&);};MyInspector :public ProcessInspector{   TcpInspector} ;那么MyInspector{  HttpServer server_;  boost::scoped_ptr<ProcessInspector> processInspector;  boost::scoped_ptr<ProcessInspector> TcpInspector;  MutexLock mutex_;  std::map<string, CommandList> commands_;  std::map<string, HelpList> helps_;}那么MyInspector 在初始化时,会初始化ProcessInspector 和TcpInspector,如果ProcessInspector初始化完毕后,启动了OnreRequest(),而TcpInspector还没注册完,也就是说TcpInspector还在add()函数中,那么不加锁的话,就会出现问题了。  */  MutexLockGuard lock(mutex_);  commands_[module][command] = cb;  helps_[module][command] = help;}void Inspector::start(){  server_.start();}void Inspector::onRequest(const HttpRequest& req, HttpResponse* resp){  if (req.path() == "/")  {    string result;    MutexLockGuard lock(mutex_);    // 遍历helps     for (std::map<string, HelpList>::const_iterator helpListI = helps_.begin();         helpListI != helps_.end();         ++helpListI)    {      const HelpList& list = helpListI->second;      for (HelpList::const_iterator it = list.begin();           it != list.end();           ++it)      {        result += "/";        result += helpListI->first;      // module        result += "/";        result += it->first;         // command        result += "\t";        result += it->second;            // help        result += "\n";      }    }    resp->setStatusCode(HttpResponse::k200Ok);    resp->setStatusMessage("OK");    resp->setContentType("text/plain");    resp->setBody(result);  }  else  {    // 以"/"进行分割,将得到的字符串保存在result中    std::vector<string> result = split(req.path());    // boost::split(result, req.path(), boost::is_any_of("/"));    //std::copy(result.begin(), result.end(), std::ostream_iterator<string>(std::cout, ", "));    //std::cout << "\n";    bool ok = false;    if (result.size() == 0)    {      // 这种情况是错误的,因此ok仍为false    }    else if (result.size() == 1)    {      // 只有module,没有command也是错的,因此ok仍为false      string module = result[0];    }    else    {      string module = result[0];      // 查找module所对应的命令列表      std::map<string, CommandList>::const_iterator commListI = commands_.find(module);      if (commListI != commands_.end())      {        string command = result[1];        const CommandList& commList = commListI->second;        // 查找command对应的命令        CommandList::const_iterator it = commList.find(command);        if (it != commList.end())        {          ArgList args(result.begin()+2, result.end());     // 传递给回调函数的参数表          if (it->second)          {            resp->setStatusCode(HttpResponse::k200Ok);            resp->setStatusMessage("OK");            resp->setContentType("text/plain");            const Callback& cb = it->second;            resp->setBody(cb(req.method(), args));       // 调用cb将返回的字符串传给setBody            ok = true;          }        }      }    }    if (!ok)    {      resp->setStatusCode(HttpResponse::k404NotFound);      resp->setStatusMessage("Not Found");    }    //resp->setCloseConnection(true);  }}




测试程序

#include <muduo/net/inspect/Inspector.h>#include <muduo/net/EventLoop.h>#include <muduo/net/EventLoopThread.h>using namespace muduo;using namespace muduo::net;int main(){  EventLoop loop;  EventLoopThread t;    // 监控线程 ,这里“线程该没有真正创建,t.startLoop()函数才是真正创建”  /*Inspector 的loop 和main thread 的loop是不一样的,也就是说,现在已经有两个loop了*/  Inspector ins(t.startLoop(), InetAddress(12345), "test");  loop.loop();}


在浏览器中输入127.0.0.1:12345/proc/status

Name:   inspector_testState:  S (sleeping)Tgid:   2030Pid:    2030PPid:   1907TracerPid:  0Uid:    1000    1000    1000    1000Gid:    1000    1000    1000    1000FDSize: 256Groups: 4 20 24 46 116 118 124 1000 VmPeak:    12348 kBVmSize:    12348 kBVmLck:         0 kBVmHWM:      1580 kBVmRSS:      1580 kBVmData:     8408 kBVmStk:       136 kBVmExe:       860 kBVmLib:      2868 kBVmPTE:        32 kBVmSwap:        0 kBThreads:    2SigQ:   0/9772SigPnd: 0000000000000000ShdPnd: 0000000000000000SigBlk: 0000000000000000SigIgn: 0000000000001000SigCgt: 0000000180000000CapInh: 0000000000000000CapPrm: 0000000000000000CapEff: 0000000000000000CapBnd: ffffffffffffffffCpus_allowed:   3Cpus_allowed_list:  0-1Mems_allowed:   1Mems_allowed_list:  0voluntary_ctxt_switches:    22nonvoluntary_ctxt_switches: 14



原创粉丝点击