项目开发时以及代码最终发布后,日志文件都是必不可少的,对于程序运行过程的调试、分析和监控都是很好的一种手段,对于多线程和多进程的开发也是很好的一种分析手段,代码中有线程ID的参数,但这里不讨论线程的东东,仅仅把自己使用过的控制日志记录文件的大小和格式化输出做一个分享。
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#include <memory.h>
#include <stdarg.h>
#include "syslog.h"
#define LOG_FILE_MAX_SIZE 200*1024 //200KB
long long g_offset = 0; // 记录最后一次写入文件的位置
void test_log(FILE *file, FILE *filebak, const char *format, ...)
{
long long time_total;
int done;
char ch;
char wzlog[256];
char buffer[1024];
// 格式化系统时间、日志内容
va_list arg;
va_start(arg, format);
vsprintf(wzlog, format, arg);
time_t time_log = time(NULL);
struct tm* tm_log = localtime(&time_log);
time_total = clock();
snprintf(buffer, 1024, "%04d-%02d-%02d %02d:%02d:%02d %012lld %s",
tm_log->tm_year+1900, tm_log->tm_mon+1, tm_log->tm_mday,
tm_log->tm_hour, tm_log->tm_min, tm_log->tm_sec,
time_total, wzlog);
// 超过文件最大限制,备份一下原来的log文件
if (g_offset > LOG_FILE_MAX_SIZE){
g_offset = 0;
fseek(file, g_offset, SEEK_SET);
fseek(filebak, g_offset, SEEK_SET);
// 备份一下log
while ((ch=fgetc(file))!=EOF) {
fputc(ch,filebak);
}
} // 如果没有超过件最大限制则接着写,超过以后则从文件头开始重新记录
// 原来的文件从文件头开始重新记录覆盖 open的时候记得选w+
fseek(file, g_offset, SEEK_SET);
fwrite(buffer, 1, strlen(buffer), file);
g_offset += strlen(buffer);
va_end(arg);
fflush(file);
}
int main()
{
int i = 0;
char file_name[256];
char fstrbak[256];
// C 库函数 int snprintf(char *str, size_t size, const char *format, ...)
// 将可变参数(...)按照 format 格式化成字符串并将字符串复制到 str 中,size 为要写入的字符的最大数目,超过 size 会被截断。
snprintf(file_name, 256, "./test_%d.log", getpid());
snprintf(fstrbak, 256, "./test_%dbak.log", getpid());
FILE *fp = fopen(file_name, "wr+");
FILE *fpbak = fopen(fstrbak, "w+");
for(i=1; i<4000; i++) {
test_log(fp, fpbak, "log test %09d\n", i);
//usleep(2);
}
fclose(fp);
fclose(fpbak);
return 0;
}
每次运行都会由新的线程ID,所以log文件名字会不同,代码中45-46行可以在两个log文件的61行对比认识一下。