tail구현 함수 입니다. 파일에 추가 되는 내용이 있는지 검사해서 줄단위로 읽어들입니다. 로그파일처리를 위한 프로그램등에 유용하게 사용할 수 있을 겁니다. 현재 저는 Apache(:12)의 웹로그를 분석해서 PV, Hits를 통계내는 곳에 사용하고 있습니다. 시간단위로 누적 count 값을 RRD(:12)에 저장해 둔다면, 변화량을 측정할 수 있게됩니다.
파일의 끝에 도달하면 select의 의미가 없으므로 <!> 굳이 select를 사용할 필요는 없을 거라고 생각된다. 실제 select부분을 주석처리해도 제대로 작동한다.
사용방법
TAIL *opentail(char *fname);
int readtail(TAIL *LTAIL, char *buf, size_t size, int sec);
void closetail(TAIL *LTAIL);
opentail은 tail(:12)을 적용할 파일을 열기 위해서 사용한다. 실패하면 NULL을 리턴하고 성공하면 TAIL 객체(구조체 포인터)를 리턴한다.
readtail은 TAIL 객체를 이용해서 파일로 부터 추가된 내용을 줄단위로 읽어 온다. 줄이 추가되면 size만큼 읽어서 buf에 복사한다. 추가된 줄이 없을 경우 sec만큼 기다린다.
입력된 줄을 읽어 왔다면 1을 리턴하고 어떤 이유로 실패 했을 경우 -1을 리턴한다.
#include "tail.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <vector>
using namespace std;
int main(int argc, char **argv)
{
vector<TAIL *> tflist;
TAIL *tf;
char *buf;
int n, i;
// 2개 이상의 파일에 대해서 tail 가능하다.
for(i = 1; i < argc; i++)
{
if((tf = opentail(argv[i])) == NULL)
{
perror("error ");
exit(1);
}
tflist.push_back(tf);
}
buf = (char *)malloc(1024);
int issleep = 0;
while(1)
{
issleep = 0;
for(i = 0; i < tflist.size(); i++)
{
n = readtail(tflist[i], buf, 1023, 1);
if(n > 0)
printf("%d : %s", i, buf);
issleep |= n;
}
if (issleep == 0)
{
sleep(1);
printf("Sleep\n");
continue;
}
}
//closetail(tf);
free(buf);
}
코드
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
/*
* tail 관리를 위한 객체
*/
typedef struct _TAIL
{
FILE *fp; // 파일 스트림
char filename[256]; // 오픈한 파일 이름
int fd; // 파일 스트림에 대한 파일 지정자
int revsize; // 최근에 읽었던 파일 크기
} TAIL;
/*
* tail을 적용할 파일을 연다.
*/
TAIL *opentail(char *fname)
{
TAIL *MTAIL;
struct stat fbuf;
MTAIL = (TAIL *)malloc(sizeof(TAIL));
if ((MTAIL->fp = fopen(fname, "r")) == NULL)
{
return NULL;
}
if (stat(fname, &fbuf) < 0)
{
return NULL;
}
strncpy(MTAIL->filename, fname, 255);
// 열린 파일 스트림의 파일지정자를 얻어온다.
MTAIL->fd = fileno(MTAIL->fp);
MTAIL->revsize = fbuf.st_size;
return MTAIL;
}
/*
* sec시간 간격으로 파일에 추가된 내용을 읽어온다.
* 만약 지금의 파일크기가 이전 파일크기 보다 작다면
* 파일이 truncate() 되었다고 가정하고 첫라인 부터
* 다시 읽어 들인다.
*/
int readtail(TAIL *LTAIL, char *buf, size_t size, int sec)
{
fd_set rfds;
struct timeval tv;
int n, retval;
char *ret;
int fd;
struct stat fbuf;
FD_ZERO(&rfds);
FD_SET(LTAIL->fd, &rfds);
tv.tv_sec = sec;
tv.tv_usec = 0;
retval = select(LTAIL->fd+1, &rfds, NULL, NULL, &tv);
if (retval)
{
ret = fgets(buf, size, LTAIL->fp);
if (stat(LTAIL->filename, &fbuf) < 0)
{
return -1;
}
if (ret == NULL)
{
// 현재 파일크기가 이전 파일 크기 보다
// 작다면 rewind()시킨다.
if (fbuf.st_size < LTAIL->revsize)
{
rewind(LTAIL->fp);
}
LTAIL->revsize = fbuf.st_size;
return 0;
}
LTAIL->revsize = fbuf.st_size;
return 1;
}
else
{
return -1;
}
return 1;
}
void closetail(TAIL *LTAIL)
{
fclose(LTAIL->fp);
free(LTAIL);
}
설명
사용방법
코드
참고문서
Recent Posts
Archive Posts
Tags