21#define TRACE_FILE_LINE_BUF 1100
24#define FILE_LOCK_TIMEOUT_MS 100
27#define TRACE_FILE_TS_LEN 23
30#define TRACE_FILE_SUFFIX_MAX 5
34#define TRACE_FILE_PATH_MAX MAX_PATH
39#define TRACE_FILE_PATH_MAX PATH_MAX
104 snprintf(buf, (
size_t)buf_size,
105 "%04d-%02d-%02d %02d:%02d:%02d.%03d",
106 (
int)st.wYear, (
int)st.wMonth, (
int)st.wDay,
107 (
int)st.wHour, (
int)st.wMinute, (
int)st.wSecond,
108 (
int)st.wMilliseconds);
112 clock_gettime(CLOCK_REALTIME, &ts);
113 gmtime_r(&ts.tv_sec, &tm_val);
118#pragma GCC diagnostic push
119#pragma GCC diagnostic ignored "-Wformat-truncation"
120 snprintf(buf, (
size_t)buf_size,
121 "%04d-%02d-%02d %02d:%02d:%02d.%03d",
122 tm_val.tm_year + 1900, tm_val.tm_mon + 1, tm_val.tm_mday,
123 tm_val.tm_hour, tm_val.tm_min, tm_val.tm_sec,
124 (
int)(ts.tv_nsec / 1000000));
125#pragma GCC diagnostic pop
142 FILE_SHARE_READ | FILE_SHARE_DELETE,
145 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
148 if (p->fh == INVALID_HANDLE_VALUE)
156 SetFilePointerEx(p->fh, pos, NULL, FILE_END);
159 if (GetFileSizeEx(p->fh, &size))
174 O_WRONLY | O_APPEND | O_CREAT | O_DSYNC,
184 if (fstat(p->
fd, &st) == 0)
210 FILE_SHARE_READ | FILE_SHARE_DELETE,
213 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
216 return (p->fh != INVALID_HANDLE_VALUE) ? 0 : -1;
220 O_WRONLY | O_APPEND | O_CREAT | O_TRUNC | O_DSYNC,
223 return (p->
fd != -1) ? 0 : -1;
233 if (p->fh != INVALID_HANDLE_VALUE)
236 p->fh = INVALID_HANDLE_VALUE;
263 snprintf(new_path,
sizeof(new_path),
"%s.%d", p->
path, p->
generations);
265 DeleteFileA(new_path);
274 snprintf(new_path,
sizeof(new_path),
"%s.%d", p->
path, gen);
280 snprintf(old_path,
sizeof(old_path),
"%s", p->
path);
284 snprintf(old_path,
sizeof(old_path),
"%s.%d", p->
path, gen - 1);
288 if (!MoveFileExA(old_path, new_path, MOVEFILE_REPLACE_EXISTING))
294 if (rename(old_path, new_path) != 0)
319 path_len = strlen(path);
334 handle->
path = (
char *)malloc(path_len + 1);
335 if (handle->
path == NULL)
340 memcpy(handle->
path, path, path_len + 1);
348 handle->fh = INVALID_HANDLE_VALUE;
349 handle->cs_initialized = 0;
350 InitializeCriticalSectionAndSpinCount(&handle->cs, 1000);
351 handle->cs_initialized = 1;
355 if (pthread_mutex_init(&handle->
mutex, NULL) != 0)
368 if (handle->cs_initialized)
370 DeleteCriticalSection(&handle->cs);
375 pthread_mutex_destroy(&handle->
mutex);
395 if (handle == NULL || message == NULL)
404 len = snprintf(buf,
sizeof(buf),
"%s %c %s\n", ts,
level_char(level), message);
409 if (len >= (
int)
sizeof(buf))
412 len = (int)
sizeof(buf) - 1;
420 while (!TryEnterCriticalSection(&handle->cs))
422 if ((LONG)(GetTickCount() - deadline) >= 0)
431 struct timespec abs_timeout;
432 clock_gettime(CLOCK_REALTIME, &abs_timeout);
434 if (abs_timeout.tv_nsec >= 1000000000L)
436 abs_timeout.tv_sec += 1;
437 abs_timeout.tv_nsec -= 1000000000L;
439 if (pthread_mutex_timedlock(&handle->
mutex, &abs_timeout) != 0)
448 if (handle->fh == INVALID_HANDLE_VALUE)
450 LeaveCriticalSection(&handle->cs);
454 if (handle->
fd == -1)
456 pthread_mutex_unlock(&handle->
mutex);
466 if (WriteFile(handle->fh, buf, (DWORD)len, &written, NULL)
467 && (DWORD)written == (DWORD)len)
474 ssize_t written = write(handle->
fd, buf, (
size_t)len);
475 if (written == (ssize_t)len)
499 LeaveCriticalSection(&handle->cs);
501 pthread_mutex_unlock(&handle->
mutex);
518 if (handle->cs_initialized)
520 DeleteCriticalSection(&handle->cs);
521 handle->cs_initialized = 0;
526 pthread_mutex_destroy(&handle->
mutex);
#define TRACE_FILE_PATH_MAX
void TRACE_FILE_UTIL_API trace_file_provider_dispose(trace_file_provider_t *handle)
ファイルトレースプロバイダを終了する。
int TRACE_FILE_UTIL_API trace_file_provider_write(trace_file_provider_t *handle, int level, const char *message)
ファイルへトレースメッセージを書き込む。
#define TRACE_FILE_TS_LEN
タイムスタンプ部分の文字数 ("YYYY-MM-DD HH:MM:SS.mmm" = 23 文字)。
#define TRACE_FILE_LINE_BUF
1 行分のスタックバッファサイズ。
static void close_file(trace_file_provider_t *p)
開いているファイルを閉じる。未開の場合は何もしない (冪等)。
#define TRACE_FILE_SUFFIX_MAX
ローテーションパスのサフィックス最大長 (".999\0" = 5 文字)。
static int open_file_truncate(trace_file_provider_t *p)
ローテーション後の新規ファイルを空で作成して開く。 current_bytes は必ず 0 に設定される。
static void format_timestamp(char *buf, int buf_size)
現在時刻を "YYYY-MM-DD HH:MM:SS.mmm" (UTC) 形式でバッファへ書き込む。
#define FILE_LOCK_TIMEOUT_MS
ファイル書き込みロック取得のタイムアウト (ミリ秒)。
static int open_file(trace_file_provider_t *p)
ファイルを追記モードで開き current_bytes を初期サイズで初期化する。
static void rotate_file(trace_file_provider_t *p)
トレースファイルをローテーションする。
static char level_char(int level)
トレースレベル整数をレベル文字に変換する。
trace_file_provider_t *TRACE_FILE_UTIL_API trace_file_provider_init(const char *path, size_t max_bytes, int generations)
ファイルトレースプロバイダを初期化する。
ファイルトレースプロバイダハンドル構造体 (内部定義)。
int fd
ファイルディスクリプタ。-1 = 未開。
char * path
ヒープ確保済みファイルパス文字列。
size_t max_bytes
ファイル 1 世代あたりの最大バイト数。
pthread_mutex_t mutex
スレッド安全のための mutex。
int mutex_initialized
mutex が初期化済みかどうかのフラグ。
int _pad_end
パディング (構造体サイズを 8 バイト境界に揃える)。
size_t current_bytes
現ファイルへの書き込み済みバイト数 (インメモリ追跡)。
#define TRACE_FILE_LV_ERROR
エラー (trace-util.h の TRACE_LV_ERROR と同値)。
#define TRACE_FILE_DEFAULT_GENERATIONS
保持するトレースファイル世代数の既定値。
#define TRACE_FILE_LV_INFO
情報 (trace-util.h の TRACE_LV_INFO と同値)。
#define TRACE_FILE_LV_WARNING
警告 (trace-util.h の TRACE_LV_WARNING と同値)。
#define TRACE_FILE_DEFAULT_MAX_BYTES
トレースファイル 1 世代あたりの既定最大サイズ (バイト)。
#define TRACE_FILE_UTIL_API
呼び出し規約マクロ。
struct trace_file_provider trace_file_provider_t
ファイルトレースプロバイダハンドル (不透明型)。
#define TRACE_FILE_LV_CRITICAL
致命的エラー (trace-util.h の TRACE_LV_CRITICAL と同値)。