source: libcf/trunk/src/cf_log.c@ 51

Last change on this file since 51 was 51, checked in by cheese, 11 years ago

#1 change the debugging utiltity to support single context with mutex

File size: 14.0 KB
Line 
1/**
2 * @file cf_log.c
3 * @author myusgun <myusgun@gmail.com>
4 * @version 0.1
5 */
6#if defined(_WIN32) || defined(_WIN64)
7# define _USE_32BIT_TIME_T
8#endif
9
10#include "cf_log.h"
11#include "cf_file.h"
12#include "cf_thread.h"
13#include "cf_local.h"
14#include "cf_error.h"
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <stdarg.h>
20#include <time.h>
21
22#if defined(_WIN32) || defined(_WIN64)
23# define snprintf _snprintf
24# include <Windows.h>
25#else
26# include <sys/time.h>
27#endif
28
29#define CHECK_INVALID_CTX(__ctx) (__ctx == NULL)
30#define LOCK_LOG_CTX(__ctx) CF_Mutex_Lock (&__ctx->mutex)
31#define UNLOCK_LOG_CTX(__ctx) CF_Mutex_Unlock (&__ctx->mutex)
32#define CHECK_INITIALIZED() (gLogArray.ctxPool == NULL|| \
33 gLogArray.ctxSize <= 0 )
34#define CHECK_INVALID_MAPID(__mapid) (gLogArray.ctxSize <= __mapid)
35#define CHECK_MAPPED_ID(__mapid) (gLogArray.ctxPool[__mapid] != NULL)
36
37#define LOG_BUFFER_DEFAULT_SIZE 128 * 1024
38
39#define LOG_DATETIME_LENGTH sizeof ("0000-00-00 00:00:00.000") - 1
40
41/**
42 * 로그 컨텍스트
43 *
44 * @remark change from public to private
45 */
46typedef void * CF_Log_Ctx;
47
48typedef struct __cf_util_datetime__
49{
50 int year;
51 int month;
52 int day;
53 int week; /* SUN:0 ~ SAT:6 */
54
55 int hour;
56 int min;
57 int sec;
58 int usec;
59} S_CF_LOG_DATETIME, CF_LOG_DATETIME;
60
61typedef struct __cf_log_ctx__ {
62 char path[NAME_LENGTH + 1];
63 int fd;
64 char * buffer;
65 size_t size; /* entire size of buffer */
66 size_t length; /* data length in current */
67 CF_Mutex mutex;
68} S_CF_LOG_CTX, CF_LOG_CTX;
69
70typedef struct __cf_log_array__ {
71 CF_Log_Ctx * ctxPool;
72 int ctxSize;
73} S_CF_LOG_ARRAY, CF_LOG_ARRAY;
74
75static CF_LOG_ARRAY gLogArray;
76
77#if defined(_WIN32) || defined(_WIN64)
78/* #if defined(_WIN32) || defined(_WIN64) {{{ */
79struct timezone
80{
81 int tz_minuteswest; /* minutes W of Greenwich */
82 int tz_dsttime; /* type of dst correction */
83};
84
85// Definition of a gettimeofday function
86int gettimeofday(struct timeval *tv, struct timezone *tz)
87{
88 // Define a structure to receive the current Windows filetime
89 FILETIME ft;
90
91 // Initialize the present time to 0 and the timezone to UTC
92 unsigned __int64 ui64 =0;
93 //static int tzflag = 0;
94
95 if (NULL != tv)
96 {
97 GetSystemTimeAsFileTime(&ft);
98
99 ui64 = (((unsigned __int64) ft.dwHighDateTime << 32)
100 + (unsigned __int64) ft.dwLowDateTime);
101
102 if (ui64)
103 {
104 ui64 /= 10;
105 ui64 -= ((369 * 365 + 89) * (unsigned __int64) 86400) * 1000000;
106 }
107
108 // Finally change microseconds to seconds and place in the seconds value.
109 // The modulus picks up the microseconds.
110 tv->tv_sec = (long)(ui64 / 1000000UL);
111 tv->tv_usec = (long)(ui64 % 1000000UL);
112 }
113
114 /*
115 if (NULL != tz)
116 {
117 if (!tzflag)
118 {
119 _tzset();
120 tzflag++;
121 }
122
123 // Adjust for the timezone west of Greenwich
124 tz->tz_minuteswest = _timezone / 60;
125 tz->tz_dsttime = _daylight;
126 }
127 */
128
129 return 0;
130}
131/* }}} #if defined(_WIN32) || defined(_WIN64) */
132#endif
133
134static int
135CF_Log_Local_GetTime (CF_LOG_DATETIME * dt)
136{
137 struct timeval timeVal;
138 struct tm * timeSt;
139
140 gettimeofday (&timeVal, NULL);
141 timeSt = localtime ((const time_t *)&timeVal.tv_sec);
142
143 dt->year = timeSt->tm_year + 1900;
144 dt->month = timeSt->tm_mon + 1;
145 dt->day = timeSt->tm_mday;
146 dt->week = timeSt->tm_wday;
147
148 dt->hour = timeSt->tm_hour;
149 dt->min = timeSt->tm_min;
150 dt->sec = timeSt->tm_sec;
151
152 dt->usec = (int) timeVal.tv_usec;
153
154 return CF_OK;
155}
156
157static int
158CF_Log_Local_GetTimeString (char * buffer)
159{
160 CF_LOG_DATETIME dt;
161 CF_Log_Local_GetTime (&dt);
162
163 snprintf (buffer, LOG_DATETIME_LENGTH,
164 "%02d-%02d-%02d %02d:%02d:%02d.%03d",
165 dt.year, dt.month, dt.day,
166 dt.hour, dt.min, dt.sec, dt.usec);
167
168 return CF_OK;
169}
170
171static int
172CF_Log_Local_Flush (CF_LOG_CTX * ctx)
173{
174 if (CF_File_Write (ctx->fd, ctx->buffer, ctx->length) < 0)
175 return CF_ERROR_LOG_FLUSH;
176
177 ctx->length = 0;
178
179 return CF_OK;
180}
181
182/**
183 * 로그 데이터 처리
184 *
185 * @return 성공 시, CF_OK; 실패 시, 오류 코드
186 *
187 * @param ctx 로그 컨텍스트
188 * @param buffer 로그 데이터
189 * @param demandSize 로그 데이터 길이
190 *
191 * @author vfire
192 */
193/* static */int
194CF_Log_Local_Push (CF_LOG_CTX * ctx,
195 const char * buffer,
196 const size_t demandSize)
197{
198 int result = CF_OK;
199
200 if( ctx->size > 0 ) /* 버퍼단위 버퍼링.... */
201 {
202 size_t writeSize;
203 size_t remainSize;
204
205 remainSize = demandSize;
206 while (remainSize)
207 {
208 writeSize = (ctx->size - ctx->length) < remainSize ? (ctx->size - ctx->length) : remainSize;
209
210 memcpy (ctx->buffer + ctx->length, buffer + demandSize - remainSize, writeSize);
211 ctx->length += writeSize;
212
213 if (ctx->length == ctx->size)
214 CF_Log_Local_Flush (ctx);
215
216 remainSize -= writeSize;
217 }
218 }
219 else /* flush되어야 함. */
220 {
221 ctx->buffer = (char *)buffer;
222 ctx->length = demandSize;
223
224 result = CF_Log_Local_Flush (ctx);
225 }
226
227 return result;
228}
229
230/**
231 * 로그 컨텍스트에 멀티쓰레드 모드 설정
232 *
233 * @return 성공 시, CF_OK; 실패 시, 오류 코드
234 *
235 * @param ctx 로그 컨텍스트
236 *
237 * @see CF_Log_UnsetMultiThread
238 */
239static int
240CF_Log_SetMultiThread (CF_Log_Ctx ctx)
241{
242 CF_LOG_CTX * context = (CF_LOG_CTX *) ctx;
243
244 if (CHECK_INVALID_CTX (ctx))
245 return CF_ERROR_LOG_INVALID_CTX;
246
247 if (CF_Mutex_Create (&context->mutex) < 0)
248 return CF_ERROR_LOG_SET_MULTITHREAD;
249
250 return CF_OK;
251}
252
253/**
254 * 로그 컨텍스트에 멀티쓰레드 모드 설정 해제
255 *
256 * @return 성공 시, CF_OK; 실패 시, 오류 코드
257 *
258 * @param ctx 로그 컨텍스트
259 *
260 * @see CF_Log_SetMultiThread
261 */
262static int
263CF_Log_UnsetMultiThread (CF_Log_Ctx ctx)
264{
265 CF_LOG_CTX * context = (CF_LOG_CTX *) ctx;
266
267 if (CHECK_INVALID_CTX (ctx))
268 return CF_ERROR_LOG_INVALID_CTX;
269
270 if (CF_Mutex_Destory (&context->mutex) < 0)
271 return CF_ERROR_LOG_UNSET_MULTITHREAD;
272
273 return CF_OK;
274}
275
276/**
277 * 로그 컨텍스트에 따라 로그 쓰기
278 *
279 * @return 성공 시, CF_OK; 실패 시, 오류 코드
280 *
281 * @param ctx 로그 컨텍스트
282 * @param prefix 로그의 프리픽스 문자열
283 * @param fmt 포맷 스트링
284 * @param ... 가변 인자
285 */
286static int
287CF_Log_WriteCtx (CF_Log_Ctx ctx,
288 const char * prefix,
289 const char * fmt,
290// ...)
291 va_list valist)
292{
293 CF_LOG_CTX * context = (CF_LOG_CTX *) ctx;
294// va_list valist;
295 char buffer[16 * 1024] = {0x00,};
296 char datetime[LOG_DATETIME_LENGTH + 1] = {0x00,};
297
298 if (CHECK_INVALID_CTX (ctx))
299 return CF_ERROR_LOG_INVALID_CTX;
300
301 LOCK_LOG_CTX (context);
302// va_start (valist, fmt);
303
304 CF_Log_Local_GetTimeString (datetime);
305 snprintf (buffer, sizeof (buffer) - 1, "[%s][%s] ", datetime, prefix);
306 vsprintf (buffer + strlen (buffer), fmt, valist);
307
308 CF_Log_Local_Push (context, buffer, strlen (buffer));
309
310// va_end (valist);
311 UNLOCK_LOG_CTX (context);
312
313 return CF_OK;
314}
315
316/**
317 * 로그 버퍼의 데이터를 즉시 로그 파일에 쓰기
318 *
319 * @return 성공 시, CF_OK; 실패 시, 오류 코드
320 *
321 * @param ctx 로그 컨텍스트
322 */
323static int
324CF_Log_FlushCtx (CF_Log_Ctx ctx)
325{
326 CF_LOG_CTX * context = (CF_LOG_CTX *) ctx;
327
328 if (CHECK_INVALID_CTX (ctx))
329 return CF_ERROR_LOG_INVALID_CTX;
330
331 LOCK_LOG_CTX (context);
332 CF_Log_Local_Flush (context);
333 UNLOCK_LOG_CTX (context);
334
335 return CF_OK;
336}
337
338/**
339 * 로그 컨텍스트 해제
340 *
341 * @return 성공 시, CF_OK; 실패 시, 오류 코드
342 *
343 * @param ctx 로그 컨텍스트
344 */
345static int
346CF_Log_DestroyCtx (CF_Log_Ctx ctx)
347{
348 CF_LOG_CTX * context = (CF_LOG_CTX *) ctx;
349
350 if (CHECK_INVALID_CTX (ctx))
351 return CF_ERROR_LOG_INVALID_CTX;
352
353 if (context->size > 0)
354 {
355 CF_Log_FlushCtx (ctx);
356 free (context->buffer);
357 context->buffer = NULL;
358 context->size = 0;
359 }
360
361 CF_File_Close (context->fd);
362
363 CF_Mutex_Destory (&context->mutex);
364 context->mutex = NULL;
365
366 return CF_OK;
367}
368
369/**
370 * 로그 컨텍스트 생성
371 *
372 * @return 성공 시, 로그 컨텍스트; 실패 시, NULL
373 *
374 * @param path 로그 파일 경로
375 * @param memsize 로그 버퍼 크기
376 * @param ctx 로그 컨텍스트 받을 주소
377 *
378 * @see CF_LOG_BUFFER_DEFAULT, CF_LOG_BUFFER_NO
379 */
380static int
381CF_Log_CreateCtx (const char * path,
382 const int memsize,
383 CF_Log_Ctx * ctx)
384{
385 int result = 0;
386 int size = (memsize == CF_LOG_BUFFER_DEFAULT)
387 ? LOG_BUFFER_DEFAULT_SIZE
388 : memsize;
389 CF_LOG_CTX * context = NULL;
390
391 if (path == NULL)
392 return CF_ERROR_LOG_INVALID_ARGS;
393
394 TRY
395 {
396 context = (CF_LOG_CTX *) calloc (sizeof (CF_LOG_CTX), 1);
397 if (context == NULL)
398 {
399 result = CF_ERROR_LOG_ALLOCATE_CTX;
400 TRY_BREAK;
401 }
402
403 context->fd = CF_File_Create (path);
404 if (context->fd < 0)
405 {
406 result = CF_ERROR_LOG_CREATE_FILE;
407 TRY_BREAK;
408 }
409 snprintf (context->path, sizeof (context->path) -1, "%s", path);
410
411 if (size > 0)
412 {
413 context->buffer = (char *) calloc ((size_t) size + 1, 1);
414 if (context->buffer == NULL)
415 {
416 result = CF_ERROR_LOG_ALLOCATE_BUFFER;
417 TRY_BREAK;
418 }
419 context->size = (size_t) size;
420 }
421 }
422 CATCH_IF (result < 0)
423 {
424 CF_Log_DestroyCtx ((CF_Log_Ctx) context);
425 return result;
426 }
427
428 *ctx = (CF_Log_Ctx) context;
429
430 return CF_OK;
431}
432
433/**
434 * 로그 컨텍스트에 아이디 넘버 할당<br />
435 * 로그 기록 시, 아이디 넘버를 사용하면 해당 로그로 기록할 수 있음
436 *
437 * @return 성공 시, CF_OK; 실패 시, 오류 코드
438 *
439 * @param mapid 부여할 아이디 넘버
440 * @param ctx 로그 컨텍스트
441 *
442 * @remark 반드시 먼저 초기화 해야하며, 초기화 시에 주어진 번호보다 작은 아이디 넘버를 사용해야 함
443 *
444 * @see CF_LOG_OPEN, CF_Log_CreateCtx
445 */
446static int
447CF_Log_MapCtxID (const int mapid,
448 const CF_Log_Ctx ctx)
449{
450 int result = 0;
451
452 TRY
453 {
454 if (CHECK_INITIALIZED ())
455 {
456 result = CF_ERROR_LOG_NOT_INITIALIZE;
457 TRY_BREAK;
458 }
459 if (CHECK_INVALID_MAPID (mapid))
460 {
461 result = CF_ERROR_LOG_INVALID_MAPID;
462 TRY_BREAK;
463 }
464 if (CHECK_MAPPED_ID (mapid))
465 {
466 result = CF_ERROR_LOG_ALREADY_MAPPED_ID;
467 TRY_BREAK;
468 }
469 }
470 CATCH_IF (result < 0)
471 {
472 CF_Log_DestroyCtx (ctx);
473 return result;
474 }
475
476 gLogArray.ctxPool[mapid] = ctx;
477
478 return CF_OK;
479}
480
481/**
482 * 아이디 넘버에 해당하는 로그를 닫고 해당하는 컨텍스트를 해제
483 *
484 * @return 성공 시, CF_OK; 실패 시, 오류 코드
485 *
486 * @param mapid 로그의 아이디 넘버
487 *
488 * @remark 아이디 넘버에 해당하는 컨텍스트가 해제되므로 주의
489 *
490 * @see CF_LOG_CLOSE, CF_Log_DestroyCtx
491 */
492static int
493CF_Log_UnmapCtxID (const int mapid)
494{
495 if (CHECK_INITIALIZED ())
496 return CF_ERROR_LOG_NOT_INITIALIZE;
497 if (CHECK_INVALID_MAPID (mapid))
498 return CF_ERROR_LOG_INVALID_MAPID;
499 if (!CHECK_MAPPED_ID (mapid))
500 return CF_ERROR_LOG_NOT_MAPPED_ID;
501
502 CF_Log_DestroyCtx (gLogArray.ctxPool[mapid]);
503
504 free (gLogArray.ctxPool[mapid]);
505 gLogArray.ctxPool[mapid] = NULL;
506
507 return CF_OK;
508}
509
510/**
511 * 아이디 넘버에 해당하는 로그 컨텍스트를 얻기
512 *
513 * @return 성공 시, CF_OK; 실패 시, 오류 코드
514 *
515 * @param mapid 로그의 아이디 넘버
516 * @param ctx 로그 컨텍스트 받을 주소
517 */
518static int
519CF_Log_GetMappedCtx (const int mapid,
520 CF_Log_Ctx * ctx)
521{
522 if (CHECK_INITIALIZED ())
523 return CF_ERROR_LOG_NOT_INITIALIZE;
524 if (CHECK_INVALID_MAPID (mapid))
525 return CF_ERROR_LOG_INVALID_MAPID;
526 if (!CHECK_MAPPED_ID (mapid))
527 return CF_ERROR_LOG_NOT_MAPPED_ID;
528
529 *ctx = gLogArray.ctxPool[mapid];
530
531 return CF_OK;
532}
533
534/**
535 * 로그를 사용하기 위해 초기화
536 *
537 * @return 성공 시, CF_OK; 실패 시, 오류 코드
538 *
539 * @param logPool 아이디 넘버 최대 값
540 */
541int
542CF_Log_Initialize (const int logPool)
543{
544 memset (&gLogArray, 0x00, sizeof (CF_LOG_ARRAY));
545
546 if (logPool > 0)
547 {
548 gLogArray.ctxPool =
549 (CF_Log_Ctx *) calloc ((size_t) logPool, sizeof (CF_Log_Ctx));
550 if (gLogArray.ctxPool == NULL)
551 return CF_ERROR_LOG_INITIALIZE;
552 gLogArray.ctxSize = logPool;
553 }
554
555 return CF_OK;
556}
557
558/**
559 * 로그가 모두 사용된 후 자원 해제
560 *
561 * @return CF_OK 반환
562 */
563int
564CF_Log_Finalize (void)
565{
566 int mapid = 0;
567
568 for (mapid = 0 ; mapid < gLogArray.ctxSize ; mapid++)
569 {
570 CF_Log_UnmapCtxID (mapid);
571 }
572
573 if (gLogArray.ctxPool != NULL)
574 free (gLogArray.ctxPool);
575
576 memset (&gLogArray, 0x00, sizeof (CF_LOG_ARRAY));
577
578 return CF_OK;
579}
580
581/**
582 * 로그 열기
583 *
584 * @return 성공 시, CF_OK; 실패 시, 오류 코드
585 *
586 * @param mapid 로그의 아이디 넘버
587 * @param path 로그 파일 경로
588 * @param memsize 로그 버퍼 크기
589 *
590 * @see CF_LOG_BUFFER_DEFAULT, CF_LOG_BUFFER_NO
591 */
592int
593CF_Log_Open (const int mapid,
594 const char * path,
595 const int memsize)
596{
597 int result = 0;
598 CF_Log_Ctx ctx = NULL;
599
600 result = CF_Log_CreateCtx (path, memsize, &ctx);
601 if (result < 0)
602 return result;
603
604 result = CF_Log_MapCtxID (mapid, ctx);
605
606 return result;
607}
608
609/**
610 * 로그 닫기
611 *
612 * @return 성공 시, CF_OK; 실패 시, 오류 코드
613 *
614 * @param mapid 로그의 아이디 넘버
615 */
616int
617CF_Log_Close (const int mapid)
618{
619 return CF_Log_UnmapCtxID (mapid);
620}
621
622/**
623 * 로그 쓰기
624 *
625 * @return 성공 시, CF_OK; 실패 시, 오류 코드
626 *
627 * @param mapid 로그의 아이디 넘버
628 * @param prefix 로그의 프리픽스 문자열
629 * @param fmt 포맷 스트링
630 * @param ... 가변 인자
631 */
632int
633CF_Log_Write (const int mapid,
634 const char * prefix,
635 const char * fmt, ...)
636{
637 int result = 0;
638 CF_Log_Ctx ctx = NULL;
639 va_list valist;
640
641 result = CF_Log_GetMappedCtx (mapid, &ctx);
642 if (result < 0)
643 return result;
644
645 va_start (valist, fmt);
646 result = CF_Log_WriteCtx (ctx, prefix, fmt, valist);
647 va_end (valist);
648
649 return result;
650}
651
652/**
653 * 로그 버퍼의 데이터를 즉시 로그 파일에 쓰기
654 *
655 * @return 성공 시, CF_OK; 실패 시, 오류 코드
656 *
657 * @param mapid 로그의 아이디 넘버
658 */
659int
660CF_Log_Flush (const int mapid)
661{
662 int result = 0;
663 CF_Log_Ctx ctx = NULL;
664
665 result = CF_Log_GetMappedCtx (mapid, &ctx);
666 if (result < 0)
667 return result;
668
669 result = CF_Log_FlushCtx (ctx);
670
671 return result;
672}
673
674/**
675 * 로그 컨텍스트에 멀티쓰레드 모드 설정
676 *
677 * @return 성공 시, CF_OK; 실패 시, 오류 코드
678 *
679 * @param mapid 로그의 아이디 넘버
680 * @param flag 설정/해제 bool 플래그
681 *
682 * @see CF_BOOL
683 */
684int
685CF_Log_SetMT (const int mapid,
686 const CF_BOOL flag)
687{
688 int result = 0;
689 CF_Log_Ctx ctx = NULL;
690
691 result = CF_Log_GetMappedCtx (mapid, &ctx);
692 if (result < 0)
693 return result;
694
695 result = (flag == CF_TRUE)
696 ? CF_Log_SetMultiThread (ctx)
697 : CF_Log_UnsetMultiThread (ctx);
698
699 return result;
700}
Note: See TracBrowser for help on using the repository browser.