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

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

#1 modify assertion logic

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