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_[][]=xx
helps_[][]=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 buggy
std::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_test
State: S (sleeping)
Tgid: 2030
Pid: 2030
PPid: 1907
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
FDSize: 256
Groups: 4 20 24 46 116 118 124 1000
VmPeak: 12348 kB
VmSize: 12348 kB
VmLck: 0 kB
VmHWM: 1580 kB
VmRSS: 1580 kB
VmData: 8408 kB
VmStk: 136 kB
VmExe: 860 kB
VmLib: 2868 kB
VmPTE: 32 kB
VmSwap: 0 kB
Threads: 2
SigQ: 0/9772
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 0000000180000000
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: ffffffffffffffff
Cpus_allowed: 3
Cpus_allowed_list: 0-1
Mems_allowed: 1
Mems_allowed_list: 0
voluntary_ctxt_switches: 22
nonvoluntary_ctxt_switches: 14