polardbxengine/storage/xengine/core/logger/logger.h

314 lines
9.4 KiB
C++

/*
* Copyright (c) 2020, Alibaba Group Holding Limited
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef IS_LOGGER_V2_H_
#define IS_LOGGER_V2_H_
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string>
#include <string.h>
#include <pthread.h>
#include <atomic>
#include "util/to_string.h"
#include "log_module.h"
namespace xengine
{
namespace logger
{
enum InfoLogLevel : unsigned char {
DEBUG_LEVEL = 0,
INFO_LEVEL,
WARN_LEVEL,
ERROR_LEVEL,
FATAL_LEVEL,
HEADER_LEVEL,
NUM_INFO_LOG_LEVELS,
};
class Logger
{
private:
static const int64_t MAX_LOG_SIZE = 16 * 1024; //16KB
static const int64_t DEFAULT_LOG_FILE_SIZE = 256 * 1024 * 1024; //256MB
static const int64_t MAX_LOG_FILE_NAME_SIZE = 256;
static const mode_t LOG_FILE_MODE = 0644;
static const int LOG_FILE_SWITCH_CHECK_RATE = 1;
struct LogLocation
{
const char *file_name_;
const char *function_name_;
const int32_t line_num_;
LogLocation(const char *file_name, const char *function_name, const int32_t line_num)
: file_name_(file_name),
function_name_(function_name),
line_num_(line_num)
{
}
~LogLocation() {}
inline bool is_valid() const
{
return nullptr != file_name_ && nullptr != function_name_ && line_num_ >= 0;
}
};
struct LogBuffer
{
int64_t pos_;
char buf_[MAX_LOG_SIZE];
LogBuffer() : pos_(0)
{
buf_[0] = '\0';
}
~LogBuffer() {}
inline char *current() { return buf_ + pos_; }
inline int64_t remain() { return MAX_LOG_SIZE - pos_; }
inline void advance(int64_t len)
{
if(len >= 0) {
if (pos_ + len > MAX_LOG_SIZE) {
pos_ = MAX_LOG_SIZE;
} else {
pos_ += len;
}
}
}
inline void set_pos(int64_t pos) { pos_ = pos; }
inline bool is_valid()
{
return pos_ >= 0;
}
};
struct log_file_entry {
std::string log_file_path;
std::string log_file_name;
};
public:
~Logger()
{
pthread_mutex_destroy(&file_mutex_);
}
static inline Logger &get_log();
int init(const char *file_path,
InfoLogLevel log_level = INFO_LEVEL,
int64_t max_log_size = DEFAULT_LOG_FILE_SIZE);
// init with existing opened fd
int init(int fd, InfoLogLevel log_level = INFO_LEVEL);
int reinit(int fd, InfoLogLevel log_level = INFO_LEVEL);
inline void set_max_log_size(int64_t max_log_size) { max_log_size_ = max_log_size; }
void set_log_level(InfoLogLevel log_level);
void set_log_level_mod(InfoLogModule log_mod, InfoLogLevel log_level);
InfoLogLevel get_log_level_mod(InfoLogModule log_mod) {
return log_level_mod_[log_mod];
}
bool need_print(int32_t level)
{
return level >= log_level_;
}
bool need_print_mod(InfoLogModule log_mod, int32_t log_level);
/*
* print log by kv form.
* Step1: print log header
* Step2: print info_string
* Step3: print kv list
* Step4: print log tail
* Step5: write log to log file
*/
template <typename ...Args>
void print_log_kv(const char *mod_name,
const int32_t level,
const char *file_name,
const char *function_name,
const int32_t line_num,
const char *info_string,
const Args &... args);
void print_log_kv(const char *mod_name,
const int32_t level,
const char *file_name,
const char *function_name,
const int32_t line_num,
const char *info_string);
/*
* print log by fmt form
* Step1: print log header
* Step2: print fmt string
* Step3: write log to log file
*/
template <typename ...Args>
void print_log_fmt(const char *mod_name,
const int32_t level,
const char *file_name,
const char *function_name,
const int32_t line_num,
const char *fmt,
const Args &... args);
/*
* print log for compactibility XEngine's log
*/
void print_log_fmt(const char *mod_name,
const int32_t level,
const char *file_name,
const char *function_name,
const int32_t line_num,
const char *fmt,
va_list ap) __attribute__((format(gnu_printf, 7, 0)));
bool is_inited() const { return is_inited_; }
#ifndef NDEBUG
void reset() { is_inited_ = false; }
#endif
private:
Logger() : is_inited_(false),
fd_(fileno(stderr)),
log_level_(InfoLogLevel::DEBUG_LEVEL),
reserved_days_(-1),
reserved_file_num_(-1),
curr_log_size_(0),
max_log_size_(0),
force_switch_log_(true)
{
pthread_mutex_init(&file_mutex_, nullptr);
memset(file_path_, 0, MAX_LOG_FILE_NAME_SIZE);
for (int idx = 0; idx < InfoLogModule::NUM_INFO_LOG_MODULES; idx++) {
log_level_mod_[idx] = log_level_;
}
}
/*
* print log common header
* [year-month-day hour:minutes:seconds] LOG_LEVEL [thread_id] function_name(file_name:line_num)
* [1990-01-01 00:00:00] INFO [3456] print_log_header(logger_v2.h:120)
*/
void print_log_header(const char *mod_name,
const int32_t level,
const LogLocation &log_location,
LogBuffer &log_buffer);
/*
* add '\n' to log tail
*/
void print_log_tail(LogBuffer &log_buffer);
inline void print_info_string(const char *info_string, LogBuffer &log_buffer)
{
int64_t len = snprintf(log_buffer.current(), log_buffer.remain(), "%s, ", info_string);
log_buffer.advance(len);
}
void write_log(LogBuffer &log_buffer);
void swith_log_file();
inline bool file_exist(const char *file_path);
void clear_log_file();
static bool log_file_time_comp_by_name(log_file_entry &entry_a, log_file_entry &entry_b);
public:
int get_log_reserved_days() {
return reserved_days_;
}
int get_log_reserved_file_num() {
return reserved_file_num_;
}
int64_t get_log_file_size() {
return max_log_size_;
}
void set_log_reserved_days(int days) {
pthread_mutex_lock(&file_mutex_);
reserved_days_ = days;
pthread_mutex_unlock(&file_mutex_);
}
void set_log_reserved_file_num(int num) {
pthread_mutex_lock(&file_mutex_);
reserved_file_num_ = num;
pthread_mutex_unlock(&file_mutex_);
}
private:
bool external_log_;
bool is_inited_;
static const char *const err_str_[];
int32_t fd_;
char file_path_[MAX_LOG_FILE_NAME_SIZE];
InfoLogLevel log_level_;
InfoLogLevel log_level_mod_[NUM_INFO_LOG_MODULES];
int reserved_days_; //log file earlier than this will be deleted, -1 means disable this feature, set by sql client.
int reserved_file_num_; //keep reserved_file_num_ log files. double threshold control, -1 means disable, set by sql client.
static int num_log_file_switch_;
std::atomic<int64_t> curr_log_size_;
int64_t max_log_size_;
bool force_switch_log_; //force to switch log file when restart
pthread_mutex_t file_mutex_;
};
inline Logger& Logger::get_log()
{
static Logger log;
return log;
}
template <typename ...Args>
void Logger::print_log_kv(const char *mod_name,
const int32_t level,
const char *file_name,
const char *function_name,
const int32_t line_num,
const char *info_string,
const Args &...args)
{
LogLocation log_location(file_name, function_name, line_num);
if (nullptr != mod_name
&& level >= InfoLogLevel::DEBUG_LEVEL
&& level <= InfoLogLevel::FATAL_LEVEL
&& log_location.is_valid()
&& nullptr != info_string) {
LogBuffer log_buffer;
print_log_header(mod_name, level, log_location, log_buffer);
print_info_string(info_string, log_buffer);
util::databuff_print_log_kv_list(log_buffer.buf_, MAX_LOG_SIZE, log_buffer.pos_, args...) ;
print_log_tail(log_buffer);
write_log(log_buffer);
}
}
template <typename ...Args>
void Logger::print_log_fmt(const char *mod_name,
const int32_t level,
const char *file_name,
const char *function_name,
const int32_t line_num,
const char *fmt,
const Args &...args)
{
LogLocation log_location(file_name, function_name, line_num);
if (nullptr != mod_name
&& level >= InfoLogLevel::DEBUG_LEVEL
&& level <= InfoLogLevel::FATAL_LEVEL
&& log_location.is_valid()
&& nullptr != fmt) {
LogBuffer log_buffer;
print_log_header(mod_name, level, log_location, log_buffer);
util::databuff_printf(log_buffer.buf_, MAX_LOG_SIZE, log_buffer.pos_, fmt, args...);
print_log_tail(log_buffer);
write_log(log_buffer);
}
}
} // namespace logger
} // namespace xengine
#endif