关于可变参数(不定参数),以及windows下将进程的cpu,内存统计信息写到日志

单纯的写日志,没必要使用可变参数,但是不利于封装,代码难看,今天研究了一下可变参数

先查看手册:http://www.cplusplus.com/reference/cstdio/vsprintf/?kw=vsprintf 

function
<cstdio>

vsprintf

int vsprintf (char * s, const char * format, va_list arg );
Write formatted data from variable argument list to string
Composes a string with the same text that would be printed if  format was used on  printf, but using the elements in the variable argument list identified by  arg instead of additional function arguments and storing the resulting content as a  C string in the buffer pointed by  s.

Internally, the function retrieves arguments from the list identified by  arg as if  va_arg was used on it, and thus the state of  arg is likely to be altered by the call.

In any case,  arg should have been initialized by  va_start at some point before the call, and it is expected to be released by  va_end at some point after the call.

Parameters

s
Pointer to a buffer where the resulting C-string is stored.
The buffer should be large enough to contain the resulting string.
format
C string that contains a format string that follows the same specifications as  format in  printf (see  printf for details).
arg
A value identifying a variable arguments list initialized with  va_start.
va_list is a special type defined in  <cstdarg>.

Return Value

On success, the total number of characters written is returned.
On failure, a negative number is returned.

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* vsprintf example */
#include <stdio.h>
#include <stdarg.h>

void PrintFError ( const char * format, ... )
{
  char buffer[256];
  va_list args;
  va_start (args, format);
  vsprintf (buffer,format, args);
  perror (buffer);
  va_end (args);
}

int main ()
{
  FILE * pFile;
  char szFileName[]="myfile.txt";

  pFile = fopen (szFileName,"r");
  if (pFile == NULL)
    PrintFError ("Error opening '%s'",szFileName);
  else
  {
    // file successfully open
    fclose (pFile);
  }
  return 0;
}


In this example, if the file  myfile.txt does not exist,  perror is called to show an error message similar to:

Error opening file 'myfile.txt': No such file or directory

概括起来就是: 可变参数定义时候,参数列表包含... va_list等提供支持。而va_list需要头文件<stdarg.h>. 上面代码的va_start(args, format); 说,从fromat开始当做可变参数。 vsprintf(buffer, format, args); 说, 将format之后的可变参数转化为普通字符串buffer。上面代码直接printf(“%s", buffer); 得到的是 Error opening file "myfile.txt". 很常规。  
然后主函数调用中,将需要加入的变量,通过与printf类似的方式,加入。例如,需要加入两个int参数 可以 function(”%d %d“,  a, b); 依次类推。
可变字符串用起来很简单。那么其背后的原理呢? 可参见 http://renjwjx.blog.51cto.com/811549/243827 也不难理解。。

注意: log类在哪里都可以用。 而记录cpu信息的程序运行在vs2005(之后版本应该也可以),因为vc6.0对psapi.h的支持不好,可以获取cpu信息,但是获取不了内存及传输数据信息。另外,要使用psapi需要windows sdk。如果发现运行不找不到psapi.h,那么需要装windows sdk。

1.       需要psapi.h 。 需要安装windows sdk。 安装完了之后发现,有的东西还是不能用。是因为sdk对vc6.0的支持不够。后改用vs2005后解决。

2.       sdk 环境的设置。 在include 和lib 目录里面分别设置psapi.h 和psapi.lib的路径。比如:(vs2005)的路径可以通过运行


的最后一个configuration 进行设置,当然也可以手工加入,效果如下:


还需要添加附加依赖项,或者直接#pragma comment(lib, "Psapi.lib")

 



接下来写我的log 类:
//mylog.h
#ifndef MYLOG_H
#define MYLOG_H

#include <time.h>
#include <stdio.h>
#include <stdarg.h>

class Mylog_
{
public:
	Mylog_::Mylog_(const char * logname) {
		logname_ = logname;
		FILE *fp = NULL; 
		fp = fopen(logname_, "a+");
		fclose(fp);
	}
	Mylog_::~Mylog_()
	{
		if(fp != NULL)
			fclose(fp);
	}

	void Mylog_::writeLogTime()
	{
		fp = fopen(logname_, "a+");
		time(&rawtime);
		p = localtime(&rawtime);
		fprintf(fp, "%d/%d/%d ", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday);
		fprintf(fp, "%d:%d:%d	", p->tm_hour, p->tm_min, p->tm_sec);
		fclose(fp);
	}

	void Mylog_::recordMessage ( const char * format, ... )
	{
		char buffer[256];
		va_list args;
		va_start (args, format);
		vsprintf (buffer,format, args);
		fp = fopen(logname_, "a+");
		fprintf(fp, "%s\n", buffer);
		fclose(fp);
		va_end (args);
	}

public:
	const char * logname_;
	time_t rawtime;
	tm *p;
	FILE * fp;
};

#endif



为了得到cpu,内存信息,还需要:
//process_stat.h
#ifndef PROCESS_STAT_H
#define PROCESS_STAT_H

#include <windows.h>

typedef LONG64 int64_t;
typedef ULONG64 uint64_t;

int get_cpu_usage(int pid);
int get_memory_usage(int pid, uint64_t* mem, uint64_t* vmem);
int get_io_bytes(int pid, uint64_t* read_bytes, uint64_t* write_byte);
int  GetPidFromName(LPCSTR lpProcessName);

#endif

//代码源自:http://www.rosoo.net/a/201112/15557.html 在此基础上进行修改
//process_stat_win.cpp
#include <windows.h>
#include <psapi.h>
#include <assert.h>
#include "process_stat.h"
#include "process.h"
#include "Tlhelp32.h"
#include <string>
using namespace std;
//#define _WIN32_WINNT 0x0501
#pragma comment(lib, "Psapi.lib")

static uint64_t file_time_2_utc(const FILETIME* ftime)
{
	LARGE_INTEGER li;
	assert(ftime);
	li.LowPart = ftime->dwLowDateTime;
	li.HighPart = ftime->dwHighDateTime;
	return li.QuadPart;
}


static int get_processor_number()
{
	SYSTEM_INFO info;
	GetSystemInfo(&info);
	return (int)info.dwNumberOfProcessors;
}

int get_cpu_usage(int pid)
{
	static int processor_count_ = -1;
	static int64_t last_time_ = 0;
	static int64_t last_system_time_ = 0;

	FILETIME now;
	FILETIME creation_time;
	FILETIME exit_time;
	FILETIME kernel_time;
	FILETIME user_time;
	int64_t system_time;
	int64_t time;
	int64_t system_time_delta;
	int64_t time_delta;

	int cpu = -1;
	if(processor_count_ == -1)
	{
		processor_count_ =  get_processor_number();
	}
	GetSystemTimeAsFileTime(&now);

	HANDLE  hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);


	//原来版本中,hProcess 为 GetCurrentProcess()
	if(!GetProcessTimes(hProcess, &creation_time,&exit_time,
		&kernel_time, &user_time))
	{
		return -1;
	}

	system_time = (file_time_2_utc(&kernel_time)+file_time_2_utc(&user_time)) / processor_count_;
	time = file_time_2_utc(&now);
	if((last_system_time_ == 0 ) || last_time_ == 0)
	{
		last_system_time_ = system_time;
		last_time_ = time;
		return -1;
	}

	system_time_delta = system_time - last_system_time_;
	time_delta = time - last_time_;

	assert(time_delta != 0);
	if(time_delta == 0)
		return -1;
	
	cpu = (int) ((system_time_delta * 100 + time_delta / 2) / time_delta);
	last_system_time_ = system_time;
	last_time_ = time;
	return cpu;
}

int get_memory_usage(int pid, uint64_t* mem, uint64_t* vmem)
{
	PROCESS_MEMORY_COUNTERS pmc;
	HANDLE  hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
	if(GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
	{
		if(mem) *mem = pmc.WorkingSetSize;
		if(vmem) *vmem = pmc.PagefileUsage;
		return 0;
	}
	return -1;
}

int get_io_bytes(int pid, uint64_t* read_bytes, uint64_t* write_byte)
{
	IO_COUNTERS io_counter;
	HANDLE  hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);

	if(GetProcessIoCounters(hProcess, &io_counter))
	{
		if(read_bytes) *read_bytes = io_counter.ReadTransferCount;
		if(write_byte) *write_byte = io_counter.WriteTransferCount;
		return 0;
	}
	return -1;
}

/*void ReStartProcess(CString proname)
{
	bool isKill = KillProcessFromName(proname);
	if(isKill)
		printf("kill %s success\n", proname.GetBuffer(0));
	else
		printf("kill %s failed\n", proname.GetBuffer(0));
	CString strpath1;
	strpath1 = proname;
	Sleep(1000);
	CreateNewProcess(strpath1);
	Sleep(5000);
	int i = 1;
	while (FindProcessFromName(proname) == FALSE && i < 3)
	{
		i++;
		CreateNewProcess(strpath1);
		Sleep(5000);
	}
}

BOOL CreateNewProcess(LPCSTR pszExeName)
{
	PROCESS_INFORMATION piProcInfoGPS;
	STARTUPINFO siStartupInfo;
	SECURITY_ATTRIBUTES saProcess, saThread;
	ZeroMemory( &siStartupInfo, sizeof(siStartupInfo) );
	siStartupInfo.cb = sizeof(siStartupInfo);
	saProcess.nLength = sizeof(saProcess);
	saProcess.lpSecurityDescriptor = NULL;
	saProcess.bInheritHandle = true;
	saThread.nLength = sizeof(saThread);
	saThread.lpSecurityDescriptor = NULL;
	saThread.bInheritHandle = true;
	return ::CreateProcess( NULL, (LPTSTR)pszExeName, &saProcess, &saThread, false,CREATE_DEFAULT_ERROR_MODE,
		NULL, NULL, &siStartupInfo, &piProcInfoGPS );
}

BOOL FindProcessFromName(LPCSTR lpProcessName)
{
	HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
	PROCESSENTRY32 pe; 
	pe.dwSize = sizeof(PROCESSENTRY32); 
	if(!Process32First(hSnapShot,&pe)) 
	{ 
		return FALSE; 
	} 
	CString strProcessName = lpProcessName; 
	strProcessName.MakeLower(); 
	while (Process32Next(hSnapShot,&pe)) 
	{ 
		CString scTmp = pe.szExeFile; 
		scTmp.MakeLower(); 
		if(!scTmp.Compare(strProcessName)) 
		{ 
			return TRUE; 
		} 
		scTmp.ReleaseBuffer(); 
	} 
	strProcessName.ReleaseBuffer(); 
	return FALSE; 
}

BOOL KillProcessFromName(LPCSTR lpProcessName)
{
	HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
	PROCESSENTRY32 pe; 
	pe.dwSize = sizeof(PROCESSENTRY32); 
	if(!Process32First(hSnapShot,&pe)) 
	{ 
		return FALSE; 
	} 
	CString strProcessName = lpProcessName; 
	strProcessName.MakeLower(); 
	while (Process32Next(hSnapShot,&pe)) 
	{ 
		CString scTmp = pe.szExeFile; 
		scTmp.MakeLower(); 
		if(!scTmp.Compare(strProcessName)) 
		{ 
			DWORD dwProcessID = pe.th32ProcessID; //获得pid
			HANDLE hProcess = ::OpenProcess(PROCESS_TERMINATE,FALSE,dwProcessID); //不管通过pid还是进程名字最终都是为了获得进程的句柄
			::TerminateProcess(hProcess,0); 

			CloseHandle(hProcess); 
			return TRUE; 
		} 
		scTmp.ReleaseBuffer(); 
	} 
	strProcessName.ReleaseBuffer(); 
	return FALSE; 
}*/

int  GetPidFromName(LPCSTR lpProcessName)
{
	HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
	PROCESSENTRY32 pe; 
	pe.dwSize = sizeof(PROCESSENTRY32); 
	if(!Process32First(hSnapShot,&pe)) 
	{ 
		return FALSE; 
	} 
//	CString strProcessName = lpProcessName; 
	string strProcessName(lpProcessName);

//	strProcessName.MakeLower(); 
	while (Process32Next(hSnapShot,&pe)) 
	{ 
		//这里需要
		//CString scTmp = pe.szExeFile; 
		char buffer[260];
		wcstombs(buffer, pe.szExeFile, sizeof(buffer));

		string scTmp(buffer);
		//scTmp.MakeLower(); 
		if(!scTmp.compare(strProcessName)) 
		{ 
			DWORD dwProcessID = pe.th32ProcessID; //获得pid
			return dwProcessID;
		} 
	}  
	return -1; 
}

//main.cpp
#include "process_stat.h"
#include <windows.h>
#include <stdio.h>
#include "mylog.h"

const char processName[] = "PlateSvr.exe";
const char logName[] = "log1.txt";

int main()
{
	int pid = -1;
	pid = GetPidFromName(processName);
	if(pid == -1)
	{
		printf("cann't find the process. please confirm the processName\n");
		return 0;
	}
	printf("processName = %s pid = %d\n", processName, pid);
	printf("正在记录到%s", logName);
	while(1)
	{
		int cpu;
		uint64_t mem, vmem, r, w;
		cpu = get_cpu_usage(pid);
		get_memory_usage(pid,&mem, &vmem);
		get_io_bytes(pid,&r, &w); //在本程序中没用,在别的地方有用。。

		Mylog_ log(logName);
		log.writeLogTime();
		log.recordMessage("cpu: %d%%	内存:%u KB\n", cpu, mem/1000);

		Sleep(1000); //记录间隔
	}
	return 0;
}

这些东西放在一起,应该是可以运行的,如果不能运行,有可能是环境出了什么问题。
运行效果:
关于可变参数(不定参数),以及windows下将进程的cpu,内存统计信息写到日志_第1张图片

你可能感兴趣的:(关于可变参数(不定参数),以及windows下将进程的cpu,内存统计信息写到日志)