原子日志生成器-----UNIX系统编程笔记



要生成原子日志器,就必须用单个的write调用来输出我们希望在日志中同时出现的信息。必须用标识符O_APPEND打开文件。(有这个,每次在写操作之前,文件偏移都会被设置到文件的末尾,而且在修改文件偏移和写操作之间不会出现干扰性的文件修改操作)。使用日志器,首先调用atomic_log_open创建日志文件。在完成了所有的日志操作后由,

atomic_log_close()关闭。日志器提供三种写入日志的格式:atomic_log_array,atomic_log_string ,atomic_log_printf写入的条目存储在一个临时缓冲区中。其中,前两个不处理字符串的结束符('\0'),后一个存字符串结束符。在调用atomic_log_send时,日志器用单个操作write将整个缓冲区的内容输出,并释放临时缓冲区,atomic_loc_clear清临时缓冲区。

日志库代码如下:

头文件atomic_logger.h

int atomic_log_array(char *s, int len);
int atomic_log_clear();
int atomic_log_close();
int atomic_log_open(char *fn);
int atomic_log_printf(char *fmt, ...);//可变参数列表
int atomic_log_send();
int atomic_log_string(char *s);


实现文件:atomic_logger.c

//原子日志模块的实现(其实是原子日志库)
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>//string operators function
#include <unistd.h>
#include <sys/stat.h>//file state flags

#define FILE_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define OPEN_FLAGS (O_WRONLY | O_APPEND | O_CREAT)

typedef struct list
{
    char *entry;
    int len;
    struct list *next;
}list;

static int fd = -1;
static list *first = NULL;
static list *last = NULL;

/*----------------------------------------------------
 *private function
 */
/*this is the same as write , but restarts if interrupted by a signal*/
static ssize_t my_write(int fd, void *buf, size_t size)
{
    ssize_t bytes;

    while(((bytes = write(fd, buf, size)) == -1) && (errno == EINTR));
    return bytes;
}

/* Insert an entry with the given len field, but allocate extra bytes */
/* Return a pointer to the new entry on success or NULL on failure. */

static list *insert_new_entry(int len, int extra)
{
    char *new_str;
    list *new_entry;

    new_entry = (list*) malloc(sizeof(list) + len +extra);//?
    if(new_entry == NULL)
        return NULL;
    new_str = (char*) new_entry + sizeof(list);//?
    new_entry->entry = new_str;
    new_entry->next = NULL;
    new_entry->len = len;
    if(last == NULL)
        first = new_entry;
    else
        last->next = new_entry;
    last = new_entry;
    return new_entry;
}

/* Return the sum of the lengths of all the entries. */
static int get_length()
{
    int len = 0;
    list *current;

    current = first;
    while (current != NULL)
    {
        len += current->len;
        current = current->next;
    }
    return len;
}

/* Clear the list and free all the space. */
static void clear()
{
    list *current;
    list *free_entry;

    current = first;
    while(current != NULL)
    {
        free_entry = current;
        current = current->next;
        free(free_entry);
    }
    first = NULL;
    last = NULL;
}

/*---------------------------------------------------------
 * Public functions
 */
/* Open the given file for logging.       */
/* If successful, return 0. Otherwise, return -1 with errno set. */
int atomic_log_open(char *fn)
{
    while(fd = open(fn, OPEN_FLAGS, FILE_PERMS), fd == -1 && errno == EINTR);//
    if(fd < 0) //open operator really is occured.
        return -1;
    return 0;
}

/* Insert the given array with given size in the list.  */
/* If successful , return 0. Othrewise, return -1 with errno set. */
int atomic_log_array(char *s, int len)
{
    list *new_entry;

    if(fd < 0)
    {
        errno = EINVAL;
        return -1;
    }
    new_entry = insert_new_entry(len, 1);
    if(new_entry == NULL)
        return -1;
    (void)memcpy(new_entry->entry, s, len);//memcpy will copy len bytes src to dest,
     return 0;                             //without considering the \0 among the string
}

/* Insert the given string in the list. */
/* Do not include the string terminator.  */
/* If succesful, return 0. Otherwise, return -1 with errno set. */
int atomic_log_string(char *s)
{
    return atomic_log_array(s, strlen(s));
}

/* Insert an entry in the list.             */
/* The syntax is similar to printf.      */
/* Include the string terminator but do not count it in the length. */
/* If successful, return 0. Otherwise , return -1 with errno set. */
int atomic_log_printf(char *fmt, ...)
{
    va_list ap; //可变参数使用 查看链接 http://blog.csdn.net/djinglan/article/details/8425768
    char ch;
    int len;
    list *new_entry;

    if(fd < 0)
    {
        errno = EINVAL;
        return -1;
    }
    va_start(ap, fmt); //
    len = vsnprintf(&ch, 1, fmt, ap);//?
    new_entry = insert_new_entry(len, 1);
    if(new_entry = NULL)
        return -1;
    vsprintf(new_entry->entry, fmt, ap);//?
    return 0;
}

/* Attemp to log the entries list with a single writes. */
/* clear the list if successful. */
/* If successful , return 0, Otherwise, return -1 with errno set. */
/* If the entire list cannot be logged with a single write. this is */
/* considered a failure.     */
int atomic_log_send()
{
    char *buf;
    list *current;
    int len;

    if(fd < 0)
    {
        errno = EINVAL;
        return -1;
    }
    len = get_length();
    if(len == 0)
        return 0;
    buf = (char *)malloc(len);
    if(buf == NULL)
        return -1;
    current = first;
    len = 0;
    while(current != NULL)
    {
        (void)memcpy(buf+len, current->entry, current->len);
        len += current->len;
        current = current->next;
    }
    if(my_write(fd, buf, len) != len)
    {
        free(buf);
        errno = EAGAIN;
        return -1;
    }
    free(buf);
    clear();
    return 0;
}

/* Clear the list and free all the space without logging anything */
int atomic_log_close()
{
    int retval;
    clear();
    while(retval = close(fd), retval == -1 && errno == EINTR);
    return retval;
}

以上是原子日志库,它的使用方法如下:

1、将日志文件的名字作为参数来调用atomic_log_open

2、调用atomic_log_array, atomic_log_string , 或atomic_log_printf任一函数创建消息片。

3、调用atomic_log_send来记录消息。这个日志删除了已经保存在日志器中的消息片。

4、只要需要重复2、3.

5、用atomic_log_clear来丢弃到目前为止产生的消息片,而不发送这些消息。

6、文件日志完成时,用atomic_log_close.

       记录下来的每个消息片都被放入一个链表中。函数atomic_log_send分配一个足够大的、连续的块来装载所有的消息片,将消息片拷贝到这个块中去,用单个write将

日志发送到日志文件中去。


日志库的使用:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "atomic_logger.h"

#define BUFSIZE 1024

int main(int argc, char *argv[])
{
    char buf[BUFSIZE];
    pid_t childpid = 0;
    int i, n;

    if(argc != 3)
    {
        fprintf(stderr, "Usage: %s process filename\n", argv[0]);
        return 1;
    }
    n = atoi(argv[1]);
    for(i=1; i<n; i++)
        if(childpid = fork())
            break;
    if(childpid == -1)
    {
        fprintf(stderr,"Failed to fork.\n");
        return 1;
    }
    if(atomic_log_open(argv[2]) == -1)
    {
        fprintf(stderr, "failed to open log file.\n");
        return 1;
    }
    sprintf(buf, "i:%d process:%ld", i, (long)getpid());
    atomic_log_array(buf, strlen(buf));
    sprintf(buf,"parent:%ld child:%ld\n", (long)getppid(), (long)childpid);
    atomic_log_string(buf);
    if(atomic_log_send() == -1)
    {
        fprintf(stderr, "failed to send to log file.\n");
        return 1;
    }
    atomic_log_close();
    return 0;
}










评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值