Files
chat_rebot-connect-with-one…/c/tools/log/log.c

259 lines
6.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#define _POSIX_C_SOURCE 200112L
#include "log.h"
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
int in_log(logs *log,log_manager *self)
{
if(log == NULL||self == NULL)
return -1;
log->log[MAX_LOG_LENGTH-1] = '\0';
sem_wait(&self->log_sem);//加锁
if(self->log == NULL){
self->log = log;
self->rear = log;
self->count++;
sem_post(&self->log_sem);
return self->count;
}
if(self->count == 1)
self->log->next = log;
self->count++;
log->next = NULL;
self->rear->next = log;
self->rear = log;
sem_post(&self->log_sem);
return self->count;
}
logs *out_log(log_manager *self)
{
if(self == NULL)
return NULL;
sem_wait(&self->log_sem);
logs *buf = self->log;
if(buf==NULL)
{
sem_post(&self->log_sem);
return NULL;
}
if(self->log->next ==NULL)
self->log = self->rear = NULL;
else
self->log = self->log->next;
self->count--;
sem_post(&self->log_sem);
buf->next =NULL;
return buf;
}
int sleep_with_signal(log_manager *self)
{
struct timespec ts;
int rc;
/* 计算绝对超时:当前 + 1000 s */
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
return -1; /* 罕见失败 */
ts.tv_sec += 1000;
/* 纳秒部分无需处理1000 s 整不会溢出 */
pthread_mutex_lock(&self->mtx); /* 进入临界区 */
while (1) {
rc = pthread_cond_timedwait(&self->cond, &self->mtx, &ts);
if (rc == ETIMEDOUT) { /* 1000 s 到点 */
pthread_mutex_unlock(&self->mtx);
return 1; /* 正常超时 */
}
if (rc != 0) { /* 其他错误 */
pthread_mutex_unlock(&self->mtx);
return -1;
}
/* 被 signal / broadcast 提前唤醒,检查 stop */
if (self->stop == 1) {/* 主线程要求退出 */
pthread_mutex_unlock(&self->mtx);
return 0; /* 告诉调用者:该结束了 */
}
}
}
int cleanup(log_manager *self)
{
if(self->log ==NULL)
return 1;
logs *tobeclean,*loc;
sem_wait(&self->log_sem);//获取信号量
loc = self->log;
self->log = NULL;
self->count = 0;//摘取log链
sem_post(&self->log_sem);
//释放信号量
char *logbuf;
void *logbufbk;
char failback[MAX_LOG_LENGTH];
logbuf = (char*)malloc(1);
logbuf[0] = '\0';
size_t buf_length,buf_lengthbk = 0;
while(loc->next !=NULL)
{
tobeclean = loc;
loc = loc->next;
if(logbuf != failback){
logbufbk = logbuf;
logbuf = (char*)realloc(logbuf,strlen(logbuf)+strlen(tobeclean->log)+1);//为日志分配新的内存
}
if(logbuf == NULL){
free(logbufbk);
logbuf = failback;//降级策略,堆空间不足时,使用预分配栈空间,保留最后一条日志
}
if(logbuf != failback){
buf_lengthbk = buf_length;
buf_length = strlen(logbuf)+strlen(tobeclean->log);
strcpy(logbuf+buf_lengthbk,tobeclean->log);
}
else
{
buf_length = MAX_LOG_LENGTH;
}
free(tobeclean);
}
int fd = open("log.txt",O_CREAT | O_WRONLY | O_APPEND, 0644);
if(fd == -1){
perror("file:");
free(loc);
if(logbuf != failback)
free(logbuf);
return -1;
}
if(logbuf != failback){
logbufbk = logbuf;
logbuf = (char*)realloc(logbuf,strlen(logbuf)+strlen(loc->log)+2);
if(logbuf == NULL)
{
free(logbufbk);
logbuf = failback;
strcpy(logbuf,loc->log);
buf_length = strlen(loc->log);
}
else{
buf_lengthbk = buf_length;
buf_length = strlen(logbuf)+strlen(loc->log);
strcpy(logbuf+buf_lengthbk,loc->log);
}
}
else{
strcpy(logbuf,loc->log);
buf_length = strlen(logbuf);
}
if(logbuf == failback&&buf_length>MAX_LOG_LENGTH)
logbuf[MAX_LOG_LENGTH-1] = '\0';
else{
logbuf[buf_length] = '\0';
}
free(loc);
int error_buf = write(fd,logbuf,strlen(logbuf));
if(error_buf==-1){
close(fd);
if(logbuf != failback)
free(logbuf);
return -1;
}
else if(error_buf<buf_length)
write(fd,"unknown error case log write cut down\n",38);
if(logbuf != failback)
free(logbuf);
close(fd);
return 0;
}
void log_manager_stop(log_manager *self)
{
pthread_mutex_lock(&self->mtx);
if(self->stop == 1){
pthread_mutex_unlock(&self->mtx);
return ;
}
self->stop = 1;
/* 置退出标志 */
printf("SYS:stopping loger\n");
logs *log = malloc(sizeof(logs));
strcpy(log->log,"SYS:stopping loger\n");
self->in_log(log,self);
log = malloc(sizeof(logs));
strcpy(log->log,"SYS:done\n");
printf("SYS:done\n");
self->in_log(log,self);
pthread_mutex_unlock(&self->mtx);
pthread_cond_broadcast(&self->cond); /* 唤醒所有等待线程 */
}
//定期清理函数
void *clear_log(void *self_p)
{
log_manager *self = (log_manager*)self_p;
for(;;)
{
sleep_with_signal(self);
sem_wait(&self->log_sem);
if((self->count<MAX_LOG||self->log==NULL)&&self->stop !=1){
sem_post(&self->log_sem);
continue;
}
sem_post(&self->log_sem);
cleanup(self);
if(self->stop == 1){
return NULL;
}
}
}
int init_loger(log_manager *self)
{
if(self == NULL)
{
perror("NULL\n");
return -1;
}
if(sem_init(&self->log_sem, 0,1)==-1)
return -1;
if(pthread_mutex_init(&self->mtx,NULL)==-1)
{
if(sem_destroy(&self->log_sem)==-1)
{
perror("log:");
}
return -1;
}
if(pthread_cond_init(&self->cond,NULL)==-1)
{
if(sem_destroy(&self->log_sem)==-1)
{
perror("log:");
}
if(pthread_mutex_destroy(&self->mtx)==-1)
{
perror("log:");
}
return -1;
}
self->in_log = in_log;
self->out_log = out_log;
self->clear_log = clear_log;
self->log = NULL;
self->stop = 0;
self->cleanup = cleanup;
self->count = 0;
return 0;
}