读取proc信息的可扩展实现

需求

1. 将内存、线程数等信息注册到zk上进行监控

2. 统计信息,为下一步做负载均衡做准备。

实现

本文只解决问题1。

从网上查询了下,这些信息可以从proc文件系统中获取,如果不知道proc的,可以Google下。

网上有读取proc信息的lib——libproc,即 procps, 据说htop等实现就是基于它的。

我下载下来了,include和lib都生成了,好不容易找到一篇教程,结果在

stackoverflow上,见有人说有内存泄露,需要如下方法做。

int main(int argc, char** argv)
{
 // fillarg  used for cmdline
 // fillstat used for cmd
 PROCTAB* proc = openproc(PROC_FILLARG | PROC_FILLSTAT);

 while (proc_t* proc_info = readproc(proc, NULL)) {
    // do something
    freeproc(proc_info)
 }
 closeproc(proc);
}

于是看proc_t的定义,充满了上世纪的风格,似乎迷失在信息各种信息中了,于是无奈放弃了,直接手撸吧。代码稍后附上,如下是几个关键的技术点

1. 即然shell 命名可以获取proc信息,在C中,我们可以通过popen建立管道,获取shell命令的输出。

2. 获取进程号,可以通过 getpid()

3. sizeof(xx)/sizeof(xx[0]) 可以获取数组的大小。

4. 设计了ZeroHelper 结构,方便了扩展

5. offsetof 宏用于获取元素的偏移

6. 函数指针的应用恰到好处。

#include <time.h>
#include <stddef.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include<unistd.h>
struct StatInfo
{
    time_t   start_time;
    uint32_t duration_sec;
    uint32_t conn_cnt;
    uint32_t pmem_mb;   // peak virtual memory
    uint32_t vmem_mb;   // virtual memory
    uint32_t rmem_mb;   // real memory
    uint32_t thread_cnt;// 线程数
    uint32_t cpu_usage; // cpu
};
typedef int (*convert_fn)(const char* str, void* value_ptr);
struct ZeroHelper {
    const char* key;
    uint32_t key_len;
    uint32_t value_offset;
    convert_fn fn;
};

int proc_stat_mem_convert(const char* str, void* value_ptr)
{
    uint32_t* value = (uint32_t*)value_ptr;
    while (*str && isspace(*str))
      ++str;
    *value = atoi(str);
    return 0;
}
static const ZeroHelper proc_mem_convert_array[] = {
    {"VmPeak:", sizeof("VmPeak:") - 1, offsetof(StatInfo, pmem_mb), proc_stat_mem_convert},
    {"VmSize:", sizeof("VmSize:") - 1, offsetof(StatInfo, vmem_mb), proc_stat_mem_convert},
    {"VmRSS:", sizeof("VmRSS:") - 1, offsetof(StatInfo, rmem_mb),   proc_stat_mem_convert},
    {"Threads:", sizeof("Threads:") - 1, offsetof(StatInfo, thread_cnt), proc_stat_mem_convert},
};
int fresh_memstat_info(pid_t pid, StatInfo* info)
{
    char proc_cmd [1024];
    snprintf(proc_cmd, sizeof(proc_cmd), "cat /proc/%d/status", pid);
    FILE* fp = popen(proc_cmd, "r");
    char proc_line[1024];
    const ZeroHelper* helper = &(proc_mem_convert_array[0]);
    const int kHelperLen = sizeof(proc_mem_convert_array)/sizeof(proc_mem_convert_array[0]);
    int j = 0;
    while (fgets(proc_line, sizeof(proc_line), fp) != NULL)
    {
        if (j >= kHelperLen)
        {
            break;
        }
        // 忽略 key 头部
        if (strncmp(proc_line,
                    helper->key, helper->key_len) == 0)
        {
            helper->fn(proc_line + helper->key_len,
                       (char*)info + helper->value_offset);
            ++helper;
            ++j;
        }
    }
    pclose(fp);
    return 0;
}
int main()
{
    StatInfo info;
    pid_t pid = getpid();
    fresh_memstat_info(pid, &info);
    printf("%d\t%ukB\t%ukB\t%ukB\t%u\n",
           pid,
           info.pmem_mb, info.vmem_mb,
           info.rmem_mb, info.thread_cnt);
    sleep(1000);
    return 0;
}

时间: 2024-08-06 07:58:45

读取proc信息的可扩展实现的相关文章

给虚拟机添加新硬盘并分区,fdisk查看分区,分区,重新读取分区表信息partprobe,格式化,挂载,查看分区挂载信息

1.虚拟机关机断电 2.添加硬盘 2.开机 3.fdisk -l查看刚才新添加的硬盘 [[email protected] ~]# fdisk -l 磁盘 /dev/sda:21.5 GB, 21474836480 字节,41943040 个扇区 Units = 扇区 of 1 * 512 = 512 bytes 扇区大小(逻辑/物理):512 字节 / 512 字节 I/O 大小(最小/最佳):512 字节 / 512 字节 磁盘标签类型:dos 磁盘标识符:0x000e96ef 设备 Boo

解惑:NFC手机如何轻松读取银行卡信息?

自支付宝钱包8.0推出了NFC新功能,只要将支持NFC功能的手机靠近公交卡.银行卡等带有芯片的IC卡上,可迅速读取卡内余额.卡的信息,还可以给卡进行充值,非常贴心实用. 但是很多网友表示担忧,要是别人用手机紧贴着我的银行卡,那么信息不就轻易泄露了,这样会威胁我的资金安全吗?并有不少伪专家宣称,NFC手机有可能成为黑客的"提款机",可以实现转账操作,风险很大,网友表示很担心.真实情况是什么样的呢?让我从专业的角度,给大家道出内幕. NFC(近场通信,NearFieldCommunicat

js读取cookie信息

1. 第一种方式读取cookie信息:用document.cookie.split(“; “)的方式把字符串分割成几个段,然后遍历整个数组 //javascript方法 function getCookie(name){ var arr = document.cookie.split("; "); for(var i=0,len=arr.length;i<len;i++){ var item = arr[i].split("="); if(item[0]==n

读取配置信息

ASP.NET Core的配置(1):读取配置信息 提到“配置”二字,我想绝大部分.NET开发人员脑海中会立马浮现出两个特殊文件的身影,那就是我们再熟悉不过的app.config和web.config,多年以来我们已经习惯了将结构化的配置信息定义在这两个文件之中.到了.NET Core的时候,很多我们习以为常的东西都发生了改变,其中也包括定义配置的方式.总的来说,新的配置系统显得更加轻量级,并且具有更好的扩展性,其最大的特点就是支持多样化的数据源.我们可以采用内存的变量作为配置的数据源,也可以直

如果正确读取SQL Server中的扩展事件?

SQL Server中使用扩展事件捕捉所需的信息后,可以选择存放的位置.比如说内存或文件中,但无论存在哪里,其本质都是一个大XML.因此在SQL Server中读取该XML就是解析扩展事件结果的方式. 微软官方或者一些SQL Server论坛提供了使用SQL XML解析扩展事件的脚本,如代码清单1所示. 1: WITH events_cte 2: AS ( SELECT DATEADD(mi, 3: DATEDIFF(mi, GETUTCDATE(), CURRENT_TIMESTAMP), 4

JavaWEB中读取配置信息

第一种方法是使用java.io和java.util包,缺点是路径的概念要清晰, 例子: Properties prop = new Properties(); InputStream in = getClass().getResourceAsStream("/common.properties"); try { prop.load(in); pool = new JedisPool(config, prop.getProperty("pay.redis.url"))

iOS通过app读取通讯录信息(整理)

iOS通过app读取通讯录信息,读取通讯录信息时需要加载AddressBookUI 和AddressBook两个包,并且引入头文件 #import <AddressBook/AddressBook.h> #import <AddressBookUI/AddressBookUI.h> 具体实现如下: -(void)readAllPeoples { //定义通讯录名字为addressbook ABAddressBookRef tmpAddressBook = nil; //根据系统版本

基于C++的WMI应用编程初探-读取BIOS信息

虽然VBScript等脚本语言实现WMI编程更加方便,但有些时候我们还是不得不使用C++来编程,比如说要追求更好的性能或者是一个基于C++的项目中需要这样的功能等等. 下面是用C++实现WMI编程的基本步骤,在这里,我们通过读取BIOS信息来演示如何实现.可以对照参考: http://www.qingfengju.com/article.asp?id=60(通过一个具体实例来理解WMI脚本编程-读取BIOS信息). 1.初始化COM WMI提供的API是基于COM的,所以必须首先执行CoInit

PHP文件操作 之读取目录信息

//定义一个函数 读取目录信息的函数 function dirInfo($dirName) { //判断目录是否存在 if (!file_exists($dirName)) { die('目录不存在!'); } //判断是否是目录 if (!is_dir($dirName)) { die('您所遍历的不是目录!'); } //打开目录 $d = opendir($dirName); //判断打开目录是否成功 if (!$d) { die('打开目录失败!'); } //读取目录 while ($