!5731 【需求】gs_ctl日志按照个数轮转

Merge pull request !5731 from blig/new_master
This commit is contained in:
opengauss_bot
2024-07-25 02:21:26 +00:00
committed by Gitee
3 changed files with 291 additions and 8 deletions

View File

@ -30,6 +30,8 @@
#define _WIN32_WINNT 0x0501
#endif
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <signal.h>
#include <sys/types.h>
@ -44,6 +46,7 @@
#endif
#include "postgres_fe.h"
#include "flock.h"
#ifdef WIN32_PG_DUMP
#undef PGDLLIMPORT
@ -61,10 +64,26 @@
#undef WIN32
#endif
typedef struct ToolLogInfo {
time_t mTime;
time_t cTime;
char fileName[0];
} ToolLogInfo;
#ifndef palloc
#define palloc(sz) malloc(sz)
#endif
#ifndef pfree
#define pfree(ptr) free(ptr)
#endif
#define LOG_MAX_COUNT 50
#define GS_LOCKFILE_SIZE 1024
#define curLogFileMark "-current.log"
// optimize,to suppose pirnt to file and screen
static bool allow_log_store = false;
void check_env_value_c(const char* input_env_value);
/*
* @@GaussDB@@
* Brief :
@ -195,7 +214,173 @@ static void set_log_filename(char* log_new_name, const char* log_old_name)
securec_check_c(rc, "\0", "\0");
}
static int create_log_file(const char* prefix_name, const char* log_path)
static int gs_srvtool_lock(const char *prefix_name, const char *log_dir, FILE **fd)
{
int ret;
struct stat statbuf;
int fildes = 0;
char lockfile[MAXPGPATH] = {'\0'};
ret = snprintf_s(lockfile, sizeof(lockfile), sizeof(lockfile) - 1, "%s/%s.%s", log_dir, prefix_name, "lock");
securec_check_ss_c(ret, "\0", "\0");
canonicalize_path(lockfile);
/* If lock file dose not exist, create it */
if (stat(lockfile, &statbuf) != 0) {
char content[GS_LOCKFILE_SIZE] = {0};
*fd = fopen(lockfile, PG_BINARY_W);
if (*fd == NULL) {
printf(_("%s: can't create lock file \"%s\" : %s\n"), prefix_name, lockfile, gs_strerror(errno));
exit(1);
}
fildes = fileno(*fd);
if (fchmod(fildes, S_IRUSR | S_IWUSR) == -1) {
printf(_("%s: can't chmod lock file \"%s\" : %s\n"), prefix_name, lockfile, gs_strerror(errno));
/* Close file and Nullify the pointer for retry */
fclose(*fd);
*fd = NULL;
exit(1);
}
if (fwrite(content, GS_LOCKFILE_SIZE, 1, *fd) != 1) {
fclose(*fd);
*fd = NULL;
printf(_("%s: can't write lock file \"%s\" : %s\n"), prefix_name, lockfile, gs_strerror(errno));
exit(1);
}
fclose(*fd);
*fd = NULL;
}
if ((*fd = fopen(lockfile, PG_BINARY_W)) == NULL) {
printf(_("%s: can't open lock file \"%s\" : %s\n"), prefix_name, lockfile, gs_strerror(errno));
exit(1);
}
ret = flock(fileno(*fd), LOCK_EX | LOCK_NB, 0, START_LOCATION, GS_LOCKFILE_SIZE);
return ret;
}
static inline int gs_srvtool_unlock(FILE *fd)
{
int ret = -1;
if (fd != NULL) {
ret = flock(fileno(fd), LOCK_UN, 0, START_LOCATION, GS_LOCKFILE_SIZE);
fclose(fd);
fd = NULL;
}
return ret;
}
static inline int file_time_cmp(const void *v1, const void *v2)
{
const ToolLogInfo *l1 = *(ToolLogInfo **)v1;
const ToolLogInfo *l2 = *(ToolLogInfo **)v2;
int result = l1->mTime - l2->mTime;
if (result == 0) {
return l1->cTime - l2->cTime;
}
return result;
}
static inline void free_file_list(ToolLogInfo **file_list, int count)
{
for (int i = 0; i < count; i++) {
pfree(file_list[i]);
}
pfree(file_list);
}
static inline bool str_end_with(const char *str, const char *end)
{
int slen = strlen(str);
int elen = strlen(end);
if (elen > slen) {
return false;
} else {
return (strcmp(str + slen - elen, end) == 0);
}
}
static void remove_oldest_log(const char *prefix_name, const char *log_path, int count)
{
DIR *dir = NULL;
struct dirent *de = NULL;
errno_t rc = EOK;
int file_len = strlen(prefix_name) + strlen("-yyyy-mm-dd_hhmmss.log");
size_t info_size = sizeof(ToolLogInfo) + file_len + 1;
ToolLogInfo **file_list = (ToolLogInfo **)palloc(sizeof(ToolLogInfo *) * count);
if (file_list == NULL) {
printf(_("%s: palloc memory failed! %s\n"), prefix_name, gs_strerror(errno));
return;
}
for (int i = 0; i < count; i++) {
file_list[i] = (ToolLogInfo *)palloc(info_size);
if (file_list[i] == NULL) {
printf(_("%s: palloc memory failed! %s\n"), prefix_name, gs_strerror(errno));
free_file_list(file_list, i);
return;
}
rc = memset_s(file_list[i], info_size, 0, info_size);
securec_check_c(rc, "\0", "\0");
}
if ((dir = opendir(log_path)) == NULL) {
free_file_list(file_list, count);
printf(_("%s: opendir %s failed! %s\n"), prefix_name, log_path, gs_strerror(errno));
return;
}
int slot = 0;
struct stat fst;
char pathname[MAXPGPATH] = {'\0'};
while ((de = readdir(dir)) != NULL) {
if (strncmp(de->d_name, prefix_name, strlen(prefix_name)) == 0 &&
!str_end_with(de->d_name, curLogFileMark) &&
!str_end_with(de->d_name, ".lock")) {
rc = snprintf_s(pathname, MAXPGPATH, MAXPGPATH - 1, "%s/%s", log_path, de->d_name);
securec_check_ss_c(rc, "\0", "\0");
if (stat(pathname, &fst) < 0) {
printf(_("%s: could not stat file %s\n"), prefix_name, pathname, gs_strerror(errno));
continue;
}
file_list[slot]->mTime = fst.st_mtime;
file_list[slot]->cTime = fst.st_ctime;
rc = strncpy_s(file_list[slot]->fileName, file_len + 1, de->d_name, strlen(de->d_name));
securec_check_c(rc, "\0", "\0");
slot++;
}
}
qsort(file_list, slot, sizeof(ToolLogInfo *), file_time_cmp);
printf(_("%s: log file count %d, exceeds %d, remove the oldest ones\n"), prefix_name, count, LOG_MAX_COUNT);
int remove_cnt = 0;
while (remove_cnt < count - LOG_MAX_COUNT) {
rc = snprintf_s(pathname, MAXPGPATH, MAXPGPATH - 1, "%s/%s", log_path, file_list[remove_cnt]->fileName);
securec_check_ss_c(rc, "\0", "\0");
if (remove(pathname) < 0) {
printf(_("%s: remove log file %s failed!\n"), prefix_name, pathname, gs_strerror(errno));
continue;
}
remove_cnt++;
printf(_("%s: remove log file %s successfully, remain %d files\n"), prefix_name, pathname, count - remove_cnt);
}
free_file_list(file_list, count);
(void)closedir(dir);
}
static int create_log_file(const char* prefix_name, const char* log_path, int *count)
{
#define LOG_MAX_SIZE (16 * 1024 * 1024)
#define LOG_MAX_TIMELEN 80
@ -238,7 +423,8 @@ static int create_log_file(const char* prefix_name, const char* log_path)
while (NULL != (de = readdir(dir))) {
// exist current log file
if (NULL != strstr(de->d_name, prefix_name)) {
if (NULL != strstr(de->d_name, prefix_name) && !str_end_with(de->d_name, ".lock")) {
*count += 1;
name_ptr = strstr(de->d_name, "-current.log");
if (NULL != name_ptr) {
name_ptr += strlen("-current.log");
@ -269,9 +455,8 @@ static int create_log_file(const char* prefix_name, const char* log_path)
(void)closedir(dir);
return -1;
}
is_exist = false;
}
(void)closedir(dir);
return 0;
}
}
}
@ -300,15 +485,16 @@ static int create_log_file(const char* prefix_name, const char* log_path)
(void)dup2(fd, fileno(stderr));
(void)fprintf(stderr, _("[%s]\n"), current_localtime); // add current time to log
close(fd);
*count += 1;
}
(void)closedir(dir);
return 0;
}
static void redirect_output(const char* prefix_name, const char* log_dir)
static void redirect_output(const char* prefix_name, const char* log_dir, int *count)
{
if (0 != create_log_file(prefix_name, log_dir)) {
if (0 != create_log_file(prefix_name, log_dir, count)) {
printf(_("Warning: create_log_file failed!\n"));
return;
}
@ -343,7 +529,19 @@ void init_log(char* prefix_name)
}
allow_log_store = is_redirect; // if false print to screen, if true print to file
if (true == is_redirect) {
redirect_output(prefix_name, log_dir);
int file_count = 0;
FILE *fd = NULL;
if (gs_srvtool_lock(prefix_name, log_dir, &fd) == -1) {
printf(_("another %s command is running, init_log failed!\n"), prefix_name);
exit(1);
}
redirect_output(prefix_name, log_dir, &file_count);
if (file_count > LOG_MAX_COUNT) {
remove_oldest_log(prefix_name, log_dir, file_count);
}
gs_srvtool_unlock(fd);
}
}
@ -403,4 +601,4 @@ void GenerateProgressBar(int percent, char* progressBar)
progressBar[barWidth + 1] = ']';
progressBar[barWidth + 2] = '\0';
}
}

View File

@ -16,3 +16,4 @@ multi_standby_single/hash_index
multi_standby_single/consistency.sh
multi_standby_single/wal_stat
multi_standby_single/xlog_prune
multi_standby_single/log_remove

View File

@ -0,0 +1,84 @@
#!/bin/sh
:<<!
This use case is used to check the cleanup function of the service-side
tool logs, with a maximum of 50 files retained and a maximum size of 16MB
per file. It is not only applicable to gs_ctl, but also to other tools
such as gs_restore, gs_dumpall, gs_guc, gs_dump, gs_clean, or gs_cgroup.
!
source ./util.sh
function gs_ctl_log_remove()
{
#1. set GAUSSLOG echonvironment variable
export GAUSSLOG=$GAUSSHOME/logs
#2. query database
gs_ctl query -D $primary_data_dir
if [ "$?" -ne 0 ]; then
echo "gs_ctl query error: $failed_keyword"
fi
#3. check the log count
count=`ls -l $GAUSSLOG/bin/gs_ctl | grep log | wc -l`
if [ $count -ne 1 ]; then
echo "gs_ctl create logfile error: $failed_keyword"
fi
#4. set current file full
curr=`ls -l $GAUSSLOG/bin/gs_ctl | grep current | awk '{print $9}'`
dd if=/dev/zero of=$GAUSSLOG/bin/gs_ctl/$curr bs=16M count=1
#5. create 50 log files
date=`echo $(date "+%Y-%m-%d")`
for i in `seq 1 50`
do
time=`echo $i | awk '{printf("%06d\n", $0)}'`
name="gs_ctl-""$date"_"$time".log
dd if=/dev/zero of=$GAUSSLOG/bin/gs_ctl/$name bs=16M count=1
done
#6. query database again
gs_ctl query -D $primary_data_dir
if [ "$?" -ne 0 ]; then
echo "gs_ctl query error: $failed_keyword"
fi
#7. check the remain log count
count=`ls -l $GAUSSLOG/bin/gs_ctl | grep log | wc -l`
if [ $count -ne 50 ]; then
echo "gs_ctl remove log error: $failed_keyword"
fi
#8. query concurrently, to trigger gs_ctl.lock fail
for i in `seq 1 10`
do
gs_ctl query -D $primary_data_dir &
done
}
function tear_down()
{
tms=0
#1. wait all gs_ctl query done
while true
do
count=`ps ux | grep "gs_ctl query" | grep -v grep | wc -l`
if [ $count -ne 0 -a $tms -lt 30 ]; then
let $tms+1
sleep 1
else
break
fi
done
#2. remove remain logfile
rm -rf $GAUSSLOG/bin
if [ "$?" -ne 0 ]; then
echo "remove file error: $failed_keyword"
fi
}
gs_ctl_log_remove
tear_down