RaspberrPi project source code
guowenxue
2024-05-27 2c971f2fcf6c6322a0ea584b2af4c3cef20d3d63
commit | author | age
d6b4a7 1 /*********************************************************************************
G 2  *      Copyright:  (C) 2023 LingYun IoT System Studio.
3  *                  All rights reserved.
4  *
5  *       Filename:  logger.c
6  *    Description:  This file is common logger API functions
7  *                 
8  *        Version:  1.0.0(11/08/23)
9  *         Author:  Guo Wenxue <guowenxue@gmail.com>
10  *      ChangeLog:  1, Release initial version on "11/08/23 16:18:43"
11  *                 
12  ********************************************************************************/
13
14 #include <stdio.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include <time.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <pthread.h>
24
25 #include "logger.h"
26
27 typedef void (*log_LockFn)(void *udata, int lock);
28
29 static struct {
30     char        file[32]; /* logger file name */
31     FILE       *fp;       /* logger file pointer */
32     long        size;     /* logger file max size */
33     int         level;    /* logger level */
34     log_LockFn  lockfn;   /* lock function */
35     void       *udata;    /* lock data */
36 } L;
37
38 static const char *level_names[] = {
39     "ERROR",
40     "WARN",
41     "INFO",
42     "DEBUG",
43     "TRACE"
44 };
45
46 static const char *level_colors[] = {
47     "\x1b[31m",
48     "\x1b[33m",
49     "\x1b[32m",
50     "\x1b[36m",
51     "\x1b[94m"
52 };
53
54 static inline void time_to_str(char *buf)
55 {
56     struct timeval   tv;
57     struct tm       *tm;
58     int              len;
59
60     gettimeofday(&tv, NULL);
61     tm = localtime(&tv.tv_sec);
62
63     len = sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d.%06d ",
64             tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
65             tm->tm_hour, tm->tm_min, tm->tm_sec, (int)tv.tv_usec);
66
67     buf[len] = '\0';
68 }
69
70 static void mutex_lock(void *udata, int lock)
71 {
72     int              err;
73     pthread_mutex_t *l = (pthread_mutex_t *) udata;
74
75     if (lock)
76     {
77         if ( (err = pthread_mutex_lock(l)) != 0 )
78             log_error("Unable to lock log lock: %s", strerror(err));
79     }
80     else
81     {
82         if ( (err = pthread_mutex_unlock(l) != 0) )
83             log_error("Unable to unlock log lock: %s", strerror(err));
84     }
85 }
86
87 int log_open(char *fname, int level, int size, int lock)
88 {
89     FILE            *fp;
90
91     L.level = level;
92     L.size = size*1024;
93
94     if( !fname || !strcmp(fname, "console") || !strcmp(fname, "stderr") )
95     {
96         strcpy(L.file, "console");
97         L.fp = stderr;
98         L.size = 0; /* console don't need rollback */
99     }
100     else
101     {
102         if ( !(fp = fopen(fname, "a+")) )
103         {
104             fprintf(stderr, "%s() failed: %s\n", __func__, strerror(errno));
105             return -2;
106         }
107         L.fp = fp;
108         strncpy(L.file, fname, sizeof(L.file));
109     }
110
111
112     if( lock )
113     {
114         static pthread_mutex_t     log_lock;
115
116         pthread_mutex_init(&log_lock, NULL);
117         L.udata = (void *)&log_lock;
118         L.lockfn = mutex_lock;
119     }
120
121     fprintf(L.fp, "\n");
122     log_info("logger system(%s) start: file:\"%s\", level:%s, maxsize:%luKiB\n\n",
123             LOG_VERSION, L.file, level_names[level], size);
124
125     return 0;
126 }
127
128 void log_close(void)
129 {
130     if( L.fp && L.fp!=stderr )
131         fclose(L.fp);
132
133     if (L.udata )
134         pthread_mutex_destroy( L.udata);
135 }
136
137 static void log_rollback(void)
138 {
139     char       cmd[128]={0};
140     long       fsize;
141
142     /* don't need rollback */
143     if(L.size <= 0 )
144         return ;
145
146     fsize = ftell(L.fp);
147     if( fsize < L.size )
148         return ;
149
150     /* backup current log file  */
151     snprintf(cmd, sizeof(cmd), "cp %s %s.bak", L.file, L.file);
152     system(cmd);
153
154     /* rollback file */
155     fseek(L.fp, 0, SEEK_SET);
156     truncate(L.file, 0);
157
158     fprintf(L.fp, "\n");
159     log_info("logger system(%s) rollback: file:\"%s\", level:%s, maxsize:%luKiB\n\n",
160             LOG_VERSION, L.file, level_names[L.level], L.size/1024);
161
162     return ;
163 }
164
165 void _log_write(int level, const char *file, int line, const char *fmt, ...)
166 {
167     va_list    args;
168     char       time_string[100];
169
170     if ( !L.fp || level>L.level )
171         return;
172
173     /* Acquire lock */
174     if ( L.lockfn )
175         L.lockfn(L.udata, 1);
176
177     log_rollback();
178
179     /* check and rollback file */
180     time_to_str(time_string);
181
182     /* Log to stderr */
183     if ( L.fp == stderr )
184     {
185         fprintf(L.fp, "%s %s %-5s\x1b[0m \x1b[90m%s:%03d:\x1b[0m ",
186                 time_string, level_colors[level], level_names[level], file, line);
187     }
188     else /* Log to file */
189     {
190         fprintf(L.fp, "%s %-5s %s:%03d: ", time_string, level_names[level], file, line);
191     }
192
193     va_start(args, fmt);
194     vfprintf(L.fp, fmt, args);
195     va_end(args);
196
197     fflush(L.fp);
198
199     /* Release lock */
200     if ( L.lockfn )
201         L.lockfn(L.udata, 0);
202 }
203
204
205 void log_dump(int level, const char *prompt, char *buf, size_t len)
206 {
2c971f 207     int                 i, j, ofset;
G 208     char                line[256];
209     unsigned char       c;
210     unsigned char      *buffer = (unsigned char *)buf;
d6b4a7 211
G 212     if (!L.fp || level>L.level)
213         return;
214
215     if( prompt )
2c971f 216         _log_write(level, __FILE__, __LINE__, "%s\r\n", prompt);
d6b4a7 217
2c971f 218     for(i=0; i<len; i+=16)
d6b4a7 219     {
2c971f 220         ofset = snprintf(line, sizeof(line), "%04x: ", i);
d6b4a7 221
2c971f 222         /* print hex representation, and print spaces if end of buffer */
G 223         for(j=0; j<16; j++)
d6b4a7 224         {
2c971f 225             if(i+j < len)
G 226                 ofset += snprintf(line+ofset, sizeof(line)-ofset, "%02x ", buffer[i+j]);
227             else
228                 ofset += snprintf(line+ofset, sizeof(line)-ofset, "   ");
d6b4a7 229         }
2c971f 230         ofset += snprintf(line+ofset, sizeof(line)-ofset, " ");
d6b4a7 231
2c971f 232         /* print ASCII representation */
G 233         for(j=0; j<16; j++)
d6b4a7 234         {
2c971f 235             if (i+j < len)
G 236             {
237                 c = buffer[i+j];
238                 ofset += snprintf(line+ofset, sizeof(line)-ofset, "%c", (c>=32 && c<=126) ? c : '.');
239             }
240             else
241             {
242                 ofset += snprintf(line+ofset, sizeof(line)-ofset, " ");
243             }
d6b4a7 244         }
G 245
246         if (L.fp)
2c971f 247             fprintf(L.fp, "%s\r\n", line);
d6b4a7 248     }
G 249 }
2c971f 250