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