feat: 日志增强功能
This commit is contained in:
@@ -544,9 +544,217 @@ const char *omni_path_base_name(const char *path) {
|
||||
return slash == NULL ? path : slash + 1;
|
||||
}
|
||||
|
||||
static uint64_t omni_now_monotonic_ms64(void) {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (uint64_t) ts.tv_sec * 1000ULL + (uint64_t) (ts.tv_nsec / 1000000L);
|
||||
}
|
||||
|
||||
static int omni_positive_int_env(const char *name, int default_value) {
|
||||
const char *raw = getenv(name);
|
||||
long parsed;
|
||||
char *endptr = NULL;
|
||||
|
||||
if (raw == NULL || raw[0] == '\0') {
|
||||
return default_value;
|
||||
}
|
||||
parsed = strtol(raw, &endptr, 10);
|
||||
if (endptr == raw || *endptr != '\0' || parsed <= 0) {
|
||||
return default_value;
|
||||
}
|
||||
return (int) parsed;
|
||||
}
|
||||
|
||||
static size_t omni_positive_size_env(const char *name, size_t default_value) {
|
||||
const char *raw = getenv(name);
|
||||
unsigned long long parsed;
|
||||
char *endptr = NULL;
|
||||
|
||||
if (raw == NULL || raw[0] == '\0') {
|
||||
return default_value;
|
||||
}
|
||||
parsed = strtoull(raw, &endptr, 10);
|
||||
if (endptr == raw || *endptr != '\0' || parsed == 0ULL) {
|
||||
return default_value;
|
||||
}
|
||||
return (size_t) parsed;
|
||||
}
|
||||
|
||||
static int omni_file_logger_flush_locked(omni_file_logger_t *logger, uint64_t now_ms) {
|
||||
if (logger == NULL || logger->file == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (fflush(logger->file) != 0) {
|
||||
return -1;
|
||||
}
|
||||
logger->buffered_bytes = 0U;
|
||||
logger->last_flush_monotonic_ms = now_ms;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omni_build_rotated_path(char *buffer, size_t buffer_len, const char *path, int suffix) {
|
||||
size_t path_len;
|
||||
int written;
|
||||
|
||||
if (buffer == NULL || buffer_len == 0U || path == NULL || path[0] == '\0') {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
path_len = strlen(path);
|
||||
if (path_len + 16U >= buffer_len) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
memcpy(buffer, path, path_len);
|
||||
written = snprintf(buffer + path_len, buffer_len - path_len, ".%d", suffix);
|
||||
if (written < 0 || (size_t) written >= buffer_len - path_len) {
|
||||
errno = ENAMETOOLONG;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omni_file_logger_reopen_append_locked(omni_file_logger_t *logger) {
|
||||
struct stat st;
|
||||
FILE *file;
|
||||
|
||||
if (logger == NULL || logger->path[0] == '\0') {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
file = fopen(logger->path, "ab");
|
||||
if (file == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
logger->file = file;
|
||||
logger->current_bytes = 0U;
|
||||
if (stat(logger->path, &st) == 0) {
|
||||
logger->current_bytes = (size_t) st.st_size;
|
||||
}
|
||||
logger->buffered_bytes = 0U;
|
||||
logger->last_flush_monotonic_ms = omni_now_monotonic_ms64();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omni_file_logger_recover_after_rotate_locked(omni_file_logger_t *logger, const char *rotated_current_path) {
|
||||
int reopen_errno;
|
||||
|
||||
if (omni_file_logger_reopen_append_locked(logger) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
reopen_errno = errno;
|
||||
if (rotated_current_path != NULL && rotated_current_path[0] != '\0') {
|
||||
if (rename(rotated_current_path, logger->path) == 0) {
|
||||
if (omni_file_logger_reopen_append_locked(logger) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errno = reopen_errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int omni_file_logger_rotate_locked(omni_file_logger_t *logger) {
|
||||
int index;
|
||||
int saved_errno = 0;
|
||||
int should_recover = 0;
|
||||
char rotated_current_path[PATH_MAX];
|
||||
char from_path[PATH_MAX];
|
||||
char to_path[PATH_MAX];
|
||||
|
||||
if (logger == NULL || logger->path[0] == '\0' || logger->max_bytes == 0U || logger->max_files <= 0) {
|
||||
return 0;
|
||||
}
|
||||
rotated_current_path[0] = '\0';
|
||||
if (logger->file != NULL) {
|
||||
if (omni_file_logger_flush_locked(logger, omni_now_monotonic_ms64()) != 0) {
|
||||
return -1;
|
||||
}
|
||||
should_recover = 1;
|
||||
if (fclose(logger->file) != 0) {
|
||||
logger->file = NULL;
|
||||
saved_errno = errno;
|
||||
goto recover;
|
||||
}
|
||||
logger->file = NULL;
|
||||
}
|
||||
|
||||
if (omni_build_rotated_path(from_path, sizeof(from_path), logger->path, logger->max_files) != 0) {
|
||||
saved_errno = errno;
|
||||
goto recover;
|
||||
}
|
||||
unlink(from_path);
|
||||
for (index = logger->max_files - 1; index >= 1; --index) {
|
||||
if (omni_build_rotated_path(from_path, sizeof(from_path), logger->path, index) != 0 ||
|
||||
omni_build_rotated_path(to_path, sizeof(to_path), logger->path, index + 1) != 0) {
|
||||
saved_errno = errno;
|
||||
goto recover;
|
||||
}
|
||||
if (rename(from_path, to_path) != 0 && errno != ENOENT) {
|
||||
saved_errno = errno;
|
||||
goto recover;
|
||||
}
|
||||
}
|
||||
if (omni_build_rotated_path(to_path, sizeof(to_path), logger->path, 1) != 0) {
|
||||
saved_errno = errno;
|
||||
goto recover;
|
||||
}
|
||||
if (rename(logger->path, to_path) != 0 && errno != ENOENT) {
|
||||
saved_errno = errno;
|
||||
goto recover;
|
||||
}
|
||||
snprintf(rotated_current_path, sizeof(rotated_current_path), "%s", to_path);
|
||||
|
||||
if (omni_file_logger_reopen_append_locked(logger) != 0) {
|
||||
saved_errno = errno;
|
||||
goto recover;
|
||||
}
|
||||
return 0;
|
||||
|
||||
recover:
|
||||
if (should_recover) {
|
||||
int recover_errno = saved_errno != 0 ? saved_errno : errno;
|
||||
if (omni_file_logger_recover_after_rotate_locked(logger, rotated_current_path) == 0) {
|
||||
errno = recover_errno;
|
||||
} else if (saved_errno != 0) {
|
||||
errno = saved_errno;
|
||||
}
|
||||
} else if (saved_errno != 0) {
|
||||
errno = saved_errno;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void omni_file_logger_init(omni_file_logger_t *logger, FILE *file) {
|
||||
memset(logger, 0, sizeof(*logger));
|
||||
logger->file = file;
|
||||
pthread_mutex_init(&logger->mutex, NULL);
|
||||
logger->flush_bytes = 1U;
|
||||
logger->flush_interval_ms = 0;
|
||||
logger->immediate_flush = 1;
|
||||
logger->last_flush_monotonic_ms = omni_now_monotonic_ms64();
|
||||
}
|
||||
|
||||
void omni_file_logger_init_path(omni_file_logger_t *logger, FILE *file, const char *path, int immediate_flush) {
|
||||
struct stat st;
|
||||
|
||||
omni_file_logger_init(logger, file);
|
||||
if (path != NULL && path[0] != '\0') {
|
||||
snprintf(logger->path, sizeof(logger->path), "%s", path);
|
||||
if (stat(path, &st) == 0) {
|
||||
logger->current_bytes = (size_t) st.st_size;
|
||||
}
|
||||
}
|
||||
logger->flush_bytes = omni_positive_size_env("BLITZ_JSONL_FLUSH_BYTES", 262144U);
|
||||
logger->flush_interval_ms = omni_positive_int_env("BLITZ_JSONL_FLUSH_INTERVAL_MS", 1000);
|
||||
logger->max_bytes = omni_positive_size_env("BLITZ_JSONL_ROTATE_BYTES", 134217728U);
|
||||
logger->max_files = omni_positive_int_env("BLITZ_JSONL_ROTATE_FILES", 8);
|
||||
logger->immediate_flush = immediate_flush != 0;
|
||||
}
|
||||
|
||||
void omni_file_logger_destroy(omni_file_logger_t *logger) {
|
||||
@@ -555,13 +763,32 @@ void omni_file_logger_destroy(omni_file_logger_t *logger) {
|
||||
|
||||
int omni_file_logger_write_line(omni_file_logger_t *logger, const char *line) {
|
||||
int rc = 0;
|
||||
size_t line_len;
|
||||
uint64_t now_ms;
|
||||
if (logger == NULL || logger->file == NULL || line == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
line_len = strlen(line) + 1U;
|
||||
now_ms = omni_now_monotonic_ms64();
|
||||
pthread_mutex_lock(&logger->mutex);
|
||||
if (fputs(line, logger->file) == EOF || fputc('\n', logger->file) == EOF || fflush(logger->file) != 0) {
|
||||
if (fputs(line, logger->file) == EOF || fputc('\n', logger->file) == EOF) {
|
||||
rc = -1;
|
||||
} else {
|
||||
logger->current_bytes += line_len;
|
||||
logger->buffered_bytes += line_len;
|
||||
if (logger->immediate_flush ||
|
||||
logger->buffered_bytes >= logger->flush_bytes ||
|
||||
(logger->flush_interval_ms > 0 && now_ms - logger->last_flush_monotonic_ms >= (uint64_t) logger->flush_interval_ms)) {
|
||||
if (omni_file_logger_flush_locked(logger, now_ms) != 0) {
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
if (rc == 0 && logger->max_bytes > 0U && logger->current_bytes >= logger->max_bytes) {
|
||||
if (omni_file_logger_rotate_locked(logger) != 0) {
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&logger->mutex);
|
||||
return rc;
|
||||
|
||||
Reference in New Issue
Block a user