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

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

#1 fix interface and add util module

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