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

Last change on this file since 157 was 157, checked in by cheese, 10 years ago

#1 fix memory leakage

File size: 6.5 KB
RevLine 
[23]1/**
[128]2 * \file cf_log.c
[117]3 *
[128]4 * \author myusgun <myusgun@gmail.com>
5 * \author vfire
6 *
[127]7 * \brief 로그 구현
[11]8 */
[50]9#if defined(_WIN32) || defined(_WIN64)
[14]10# define _USE_32BIT_TIME_T
[86]11# if (_MSC_VER >= 1400)
12# define localtime _localtime32
13# endif
[14]14#endif
15
[11]16#include "cf_log.h"
[12]17#include "cf_file.h"
[147]18#include "cf_mutex.h"
[12]19#include "cf_local.h"
[40]20#include "cf_error.h"
[151]21#include "cf_util.h"
[11]22
[12]23#include <stdio.h>
24#include <stdlib.h>
[11]25#include <string.h>
[12]26#include <stdarg.h>
27#include <time.h>
[11]28
[50]29#if defined(_WIN32) || defined(_WIN64)
[13]30# include <Windows.h>
[50]31#else
32#endif
[11]33
[151]34#define LOG_BUFFER_DEFAULT_SIZE 128 * 1024
35
[85]36#define ASSERT_CTX(__ctx) \
37 if (__ctx == NULL) \
38 return CF_ERROR_LOG_INVALID_CTX
39
[151]40#define ASSERT_ARGS(x) \
41 if ((x)) \
42 return CF_ERROR_LOG_INVALID_ARGS
[85]43
[151]44/** 로그 컨텍스트 (cf_ctx의 구현) */
[122]45typedef struct __cf_log_ctx__
46{
[157]47 cf_ctx file;
48 char * buffer;
49 size_t size; /* entire size of buffer */
50 size_t length; /* data length in current */
[151]51 cf_ctx mutex;
[149]52} CF_LOG_CONTEXT;
[11]53
[23]54static int
[149]55CF_Log_Local_Flush (CF_LOG_CONTEXT * ctx)
[12]56{
[151]57 if (CF_File_Write (ctx->file, ctx->buffer, ctx->length) < 0)
[12]58 return CF_ERROR_LOG_FLUSH;
59
60 ctx->length = 0;
61
62 return CF_OK;
63}
64
[35]65/**
[127]66 * 로그 데이터 처리
[35]67 *
[127]68 * \return 성공 시, CF_OK; 실패 시, 오류 코드
[35]69 *
[127]70 * \param ctx 로그 컨텍스트
71 * \param buffer 로그 데이터
72 * \param demandSize 로그 데이터 길이
[35]73 *
[119]74 * \author vfire
[35]75 */
76/* static */int
[149]77CF_Log_Local_Push (CF_LOG_CONTEXT * ctx,
78 const char * buffer,
79 const size_t demandSize)
[35]80{
[151]81 int result = 0;
[40]82
[151]83 size_t writeSize;
84 size_t remainSize;
85
[127]86 if (ctx->size > 0) /* 버퍼단위 버퍼링.... */
[35]87 {
88 remainSize = demandSize;
89 while (remainSize)
90 {
[151]91 writeSize = (ctx->size - ctx->length) < remainSize
92 ? (ctx->size - ctx->length)
93 : remainSize;
[35]94
[151]95 memcpy (ctx->buffer + ctx->length,
96 buffer + demandSize - remainSize,
97 writeSize);
[35]98 ctx->length += writeSize;
99
100 if (ctx->length == ctx->size)
101 CF_Log_Local_Flush (ctx);
102
103 remainSize -= writeSize;
104 }
105 }
[127]106 else /* flush되어야 함. */
[35]107 {
[38]108 ctx->buffer = (char *)buffer;
109 ctx->length = demandSize;
110
[40]111 result = CF_Log_Local_Flush (ctx);
[35]112 }
113
[40]114 return result;
115}
116
117/**
[127]118 * 로그 컨텍스트에 멀티쓰레드 모드 설정
[40]119 *
[127]120 * \return 성공 시, CF_OK; 실패 시, 오류 코드
[40]121 *
[127]122 * \param ctx 로그 컨텍스트
[40]123 */
[151]124int
125CF_Log_SetMultiThread (cf_ctx ctx)
[40]126{
[149]127 CF_LOG_CONTEXT * context = (CF_LOG_CONTEXT *) ctx;
[40]128
[85]129 ASSERT_CTX (ctx);
[40]130
[151]131 if (CF_Mutex_Create (&context->mutex) < 0)
[40]132 return CF_ERROR_LOG_SET_MULTITHREAD;
133
[35]134 return CF_OK;
135}
136
137/**
[127]138 * 로그 컨텍스트에 멀티쓰레드 모드 설정 해제
[35]139 *
[127]140 * \return 성공 시, CF_OK; 실패 시, 오류 코드
[40]141 *
[127]142 * \param ctx 로그 컨텍스트
[40]143 */
[151]144int
145CF_Log_UnsetMultiThread (cf_ctx ctx)
[40]146{
[149]147 CF_LOG_CONTEXT * context = (CF_LOG_CONTEXT *) ctx;
[40]148
[85]149 ASSERT_CTX (ctx);
[40]150
[151]151 if (CF_Mutex_Destory (context->mutex) < 0)
[40]152 return CF_ERROR_LOG_UNSET_MULTITHREAD;
153
[122]154 context->mutex = NULL;
155
[40]156 return CF_OK;
157}
158
159/**
[127]160 * 로그 컨텍스트에 따라 로그 쓰기
[40]161 *
[127]162 * \return 성공 시, CF_OK; 실패 시, 오류 코드
[35]163 *
[127]164 * \param ctx 로그 컨텍스트
165 * \param prefix 로그의 프리픽스 문자열
166 * \param fmt 포맷 스트링
[136]167 * \param valist 가변 인자 리스트
[35]168 */
[40]169static int
[151]170CF_Log_Local_WriteVA (CF_LOG_CONTEXT * context,
171 const char * prefix,
172 const char * fmt,
173 va_list valist)
[12]174{
[107]175#define BUF_LEN 16 * 1024
[151]176 char buffer[BUF_LEN + 1] = {0x00,};
177 char datetime[CF_UTIL_DATETIME_LENGTH + 1] = {0x00,};
178 int length = 0;
179 int result = 0;
[11]180
[151]181 CF_UTIL_DATETIME dt;
[11]182
[151]183 ASSERT_CTX (context);
184
185 CF_Util_GetCurrentTime (&dt);
186 CF_Util_GetTimeString (&dt, datetime);
[107]187 length = snprintf (buffer, BUF_LEN, "[%s][%s] ", datetime, prefix);
188 vsnprintf (&buffer[length], BUF_LEN - (size_t)length, fmt, valist);
[40]189
[136]190 CF_Mutex_Lock (context->mutex);
191 result = CF_Log_Local_Push (context, buffer, strlen (buffer));
[125]192 CF_Mutex_Unlock (context->mutex);
[40]193
[136]194 return result;
[11]195}
196
[35]197/**
[136]198 * 로그 컨텍스트에 따라 로그 쓰기
199 *
200 * \return 성공 시, CF_OK; 실패 시, 오류 코드
201 *
202 * \param ctx 로그 컨텍스트
203 * \param prefix 로그의 프리픽스 문자열
204 * \param fmt 포맷 스트링
205 * \param ... 가변 인자
206 */
207int
[151]208CF_Log_Write (cf_ctx ctx,
209 const char * prefix,
210 const char * fmt, ...)
[136]211{
[151]212 CF_LOG_CONTEXT * context = (CF_LOG_CONTEXT *) ctx;
213
[136]214 int result = 0;
215 va_list valist;
216
217 va_start (valist, fmt);
[151]218 result = CF_Log_Local_WriteVA (context, prefix, fmt, valist);
[136]219 va_end (valist);
220
221 return result;
222}
223
224/**
[127]225 * 로그 버퍼의 데이터를 즉시 로그 파일에 쓰기
[35]226 *
[127]227 * \return 성공 시, CF_OK; 실패 시, 오류 코드
[40]228 *
[127]229 * \param ctx 로그 컨텍스트
[35]230 */
[151]231int
232CF_Log_Flush (cf_ctx ctx)
[11]233{
[151]234 int result = 0;
[19]235
[151]236 CF_LOG_CONTEXT * context = (CF_LOG_CONTEXT *) ctx;
237
[85]238 ASSERT_CTX (ctx);
[40]239
[137]240 CF_Mutex_Lock (context->mutex);
241 result = CF_Log_Local_Flush (context);
[125]242 CF_Mutex_Unlock (context->mutex);
[40]243
[136]244 return result;
[40]245}
246
247/**
[127]248 * 로그 컨텍스트 해제
[40]249 *
[127]250 * \return 성공 시, CF_OK; 실패 시, 오류 코드
[40]251 *
[127]252 * \param ctx 로그 컨텍스트
[40]253 */
[151]254int
255CF_Log_Destroy (cf_ctx ctx)
[40]256{
[149]257 CF_LOG_CONTEXT * context = (CF_LOG_CONTEXT *) ctx;
[40]258
[85]259 ASSERT_CTX (ctx);
[40]260
261 if (context->size > 0)
[19]262 {
[151]263 CF_Log_Flush (ctx);
[40]264 free (context->buffer);
265 context->buffer = NULL;
266 context->size = 0;
[19]267 }
268
[151]269 CF_File_Close (context->file);
[19]270
[151]271 CF_Mutex_Destory (context->mutex);
[45]272 context->mutex = NULL;
[11]273
[151]274 free (context);
275
[11]276 return CF_OK;
277}
[12]278
[35]279/**
[127]280 * 로그 컨텍스트 생성
[35]281 *
[127]282 * \return 성공 시, 로그 컨텍스트; 실패 시, NULL
[35]283 *
[127]284 * \param ctx 로그 컨텍스트 주소
285 * \param path 로그 파일 경로
286 * \param memsize 로그 버퍼 크기
[35]287 *
[119]288 * \see CF_LOG_DEFAULT_BUFFER, CF_LOG_NO_BUFFER
[35]289 */
[151]290int
291CF_Log_Create (cf_ctx * ctx,
292 const char * path,
293 const int memsize)
[12]294{
295 int result = 0;
[93]296 int fileFlag = CF_FILE_CREATE|CF_FILE_WRITE|CF_FILE_APPEND;
[103]297 int size = (memsize == CF_LOG_DEFAULT_BUFFER)
[42]298 ? LOG_BUFFER_DEFAULT_SIZE
[12]299 : memsize;
[87]300
[151]301 CF_LOG_CONTEXT * context = NULL;
[12]302
[151]303 ASSERT_CTX (ctx);
304 ASSERT_ARGS (path == NULL);
[12]305
306 TRY
307 {
[151]308 context = NEWCTX (CF_LOG_CONTEXT);
[12]309 if (context == NULL)
310 {
[109]311 result = CF_ERROR_LOG_CREATE_CTX;
[12]312 TRY_BREAK;
313 }
314
[151]315 result = CF_File_Open (&context->file, path, fileFlag);
316 if (result < 0)
[12]317 {
[40]318 result = CF_ERROR_LOG_CREATE_FILE;
[12]319 TRY_BREAK;
320 }
321
322 if (size > 0)
323 {
324 context->buffer = (char *) calloc ((size_t) size + 1, 1);
325 if (context->buffer == NULL)
326 {
[40]327 result = CF_ERROR_LOG_ALLOCATE_BUFFER;
[12]328 TRY_BREAK;
329 }
330 context->size = (size_t) size;
331 }
[87]332
[151]333 *ctx = (cf_ctx) context;
[12]334 }
335 CATCH_IF (result < 0)
336 {
[151]337 CF_Log_Destroy ((cf_ctx) context);
[12]338 }
339
[93]340 return result;
[12]341}
Note: See TracBrowser for help on using the repository browser.