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