core/logger/Logger.h (96 lines of code) (raw):
/*
* Copyright 2022 iLogtail Authors
*
* 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.
*/
#pragma once
#include <fstream>
#include <map>
#include <sstream>
#include "spdlog/spdlog.h"
namespace logtail {
class Logger {
const std::string DEFAULT_LOGGER_NAME = "/";
const std::string DEFAULT_PATTERN = "[%Y-%m-%d %H:%M:%S.%f]\t[%l]\t[%t]\t%v";
public:
using logger = std::shared_ptr<spdlog::logger>;
static Logger& Instance();
void InitGlobalLoggers();
logger CreateLogger(const std::string& loggerName,
const std::string& logFilePath,
unsigned int maxLogFileNum,
unsigned long long maxLogFileSize,
unsigned int maxDaysFromModify = 0, // Not supported
const std::string compress = ""); // Not supported
// If not found, return the default logger.
logger GetLogger(const std::string& loggerName);
private:
Logger();
~Logger();
// Use it to log something during intiliazing logger, it will
// be closed if logger has already been initialized successfully.
std::ofstream mInnerLogger;
void LogMsg(const std::string& msg);
struct SinkConfig {
std::string type;
unsigned int maxLogFileNum;
unsigned long long maxLogFileSize;
unsigned int maxDaysFromModify; // Not supported.
std::string logFilePath;
std::string compress; // Not supported
};
struct LoggerConfig {
std::string sinkName;
spdlog::level::level_enum level;
};
// Try to load config, if failed, use default config.
void LoadConfig(const std::string& filePath);
// Save config in JSON to @filePath.
void SaveConfig(const std::string& filePath,
std::map<std::string, LoggerConfig>& loggerCfgs,
std::map<std::string, SinkConfig>& sinkCfgs);
// LoadDefaultConfig only loads the default ("/") into @loggerCfgs and @sinkCfgs.
void LoadDefaultConfig(std::map<std::string, LoggerConfig>& loggerCfgs,
std::map<std::string, SinkConfig>& sinkCfgs);
// LoadAllDefaultConfigs loads all default configs into @loggerCfgs and @sinkCfgs.
void LoadAllDefaultConfigs(std::map<std::string, LoggerConfig>& loggerCfgs,
std::map<std::string, SinkConfig>& sinkCfgs);
// EnsureSnapshotDirExist ensures the snapshot dir exists.
void EnsureSnapshotDirExist(std::map<std::string, SinkConfig>& sinkCfgs);
};
} // namespace logtail
class LogMaker {
std::ostringstream mOStringStream;
public:
template <typename T>
LogMaker& operator()(const std::string& key, const T& value) {
return this->operator()(key.c_str(), value);
}
template <typename T>
LogMaker& operator()(const char* key, const T& value) {
mOStringStream << "\t" << key << ":" << value;
return *this;
}
LogMaker& operator()(const std::string& key, bool value) {
return this->operator()(key.c_str(), value ? "true" : "false");
}
LogMaker& operator()(const char* key, bool value) { return this->operator()(key, value ? "true" : "false"); }
const std::string GetContent() const { return mOStringStream.str(); }
};
#define LOG_X_IF(logger, condition, fields, level) \
do { \
if (condition && logger->should_log(level)) { \
LogMaker maker; \
(void)maker fields; \
logger->log(level, "{}:{}\t{}", __FILE__, __LINE__, maker.GetContent()); \
} \
} while (0)
#define SHOULD_LOG(logger, level) logger->should_log(level)
#define SHOULD_LOG_TRACE(logger) SHOULD_LOG(logger, spdlog::level::trace)
#define SHOULD_LOG_DEBUG(logger) SHOULD_LOG(logger, spdlog::level::debug)
#define SHOULD_LOG_INFO(logger) SHOULD_LOG(logger, spdlog::level::info)
#define SHOULD_LOG_WARNING(logger) SHOULD_LOG(logger, spdlog::level::warn)
#define SHOULD_LOG_ERROR(logger) SHOULD_LOG(logger, spdlog::level::err)
#define SHOULD_LOG_FATAL(logger) SHOULD_LOG(logger, spdlog::level::info)
#ifndef LOG_INFO
#define LOG_TRACE(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::trace)
#define LOG_DEBUG(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::debug)
#define LOG_INFO(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::info)
#define LOG_WARNING(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::warn)
#define LOG_ERROR(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::err)
#define LOG_FATAL(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::info)
#endif
// For compatibility with syslog.
#define APSARA_LOG_DEBUG(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::debug)
#define APSARA_LOG_INFO(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::info)
#define APSARA_LOG_WARNING(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::warn)
#define APSARA_LOG_ERROR(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::err)
#define APSARA_LOG_FATAL(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::info)
#define APSARA_LOG_TRACE(logger, fields) LOG_X_IF(logger, true, fields, spdlog::level::trace)
// Global loggers.
// NOTE: Please call Logger::Instance().InitGlobalLoggers() to init these loggers in main().
extern logtail::Logger::logger sLogger;