::value, void>::type
-safeDelete(T*& pointer) {
- if (pointer == nullptr)
- return;
- delete pointer;
- pointer = nullptr;
-}
-/// @brief Bitwise operations for C++11 strong enum class. This casts e into Flag_T and returns value after bitwise operation
-/// Use these function as flag = bitwise::Or(MyEnum::val1, flag);
-namespace bitwise {
-template
-static inline base::type::EnumType And(Enum e, base::type::EnumType flag) {
- return static_cast(flag) & static_cast(e);
-}
-template
-static inline base::type::EnumType Not(Enum e, base::type::EnumType flag) {
- return static_cast(flag) & ~(static_cast(e));
-}
-template
-static inline base::type::EnumType Or(Enum e, base::type::EnumType flag) {
- return static_cast(flag) | static_cast(e);
-}
-} // namespace bitwise
-template
-static inline void addFlag(Enum e, base::type::EnumType* flag) {
- *flag = base::utils::bitwise::Or(e, *flag);
-}
-template
-static inline void removeFlag(Enum e, base::type::EnumType* flag) {
- *flag = base::utils::bitwise::Not(e, *flag);
-}
-template
-static inline bool hasFlag(Enum e, base::type::EnumType flag) {
- return base::utils::bitwise::And(e, flag) > 0x0;
-}
-} // namespace utils
-namespace threading {
-#if ELPP_THREADING_ENABLED
-# if !ELPP_USE_STD_THREADING
-namespace internal {
-/// @brief A mutex wrapper for compiler that dont yet support std::recursive_mutex
-class Mutex : base::NoCopy {
- public:
- Mutex(void) {
-# if ELPP_OS_UNIX
- pthread_mutexattr_t attr;
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
- pthread_mutex_init(&m_underlyingMutex, &attr);
- pthread_mutexattr_destroy(&attr);
-# elif ELPP_OS_WINDOWS
- InitializeCriticalSection(&m_underlyingMutex);
-# endif // ELPP_OS_UNIX
- }
-
- virtual ~Mutex(void) {
-# if ELPP_OS_UNIX
- pthread_mutex_destroy(&m_underlyingMutex);
-# elif ELPP_OS_WINDOWS
- DeleteCriticalSection(&m_underlyingMutex);
-# endif // ELPP_OS_UNIX
- }
-
- inline void lock(void) {
-# if ELPP_OS_UNIX
- pthread_mutex_lock(&m_underlyingMutex);
-# elif ELPP_OS_WINDOWS
- EnterCriticalSection(&m_underlyingMutex);
-# endif // ELPP_OS_UNIX
- }
-
- inline bool try_lock(void) {
-# if ELPP_OS_UNIX
- return (pthread_mutex_trylock(&m_underlyingMutex) == 0);
-# elif ELPP_OS_WINDOWS
- return TryEnterCriticalSection(&m_underlyingMutex);
-# endif // ELPP_OS_UNIX
- }
-
- inline void unlock(void) {
-# if ELPP_OS_UNIX
- pthread_mutex_unlock(&m_underlyingMutex);
-# elif ELPP_OS_WINDOWS
- LeaveCriticalSection(&m_underlyingMutex);
-# endif // ELPP_OS_UNIX
- }
-
- private:
-# if ELPP_OS_UNIX
- pthread_mutex_t m_underlyingMutex;
-# elif ELPP_OS_WINDOWS
- CRITICAL_SECTION m_underlyingMutex;
-# endif // ELPP_OS_UNIX
-};
-/// @brief Scoped lock for compiler that dont yet support std::lock_guard
-template
-class ScopedLock : base::NoCopy {
- public:
- explicit ScopedLock(M& mutex) {
- m_mutex = &mutex;
- m_mutex->lock();
- }
-
- virtual ~ScopedLock(void) {
- m_mutex->unlock();
- }
- private:
- M* m_mutex;
- ScopedLock(void);
-};
-} // namespace internal
-typedef base::threading::internal::Mutex Mutex;
-typedef base::threading::internal::ScopedLock ScopedLock;
-# else
-typedef std::recursive_mutex Mutex;
-typedef std::lock_guard ScopedLock;
-# endif // !ELPP_USE_STD_THREADING
-#else
-namespace internal {
-/// @brief Mutex wrapper used when multi-threading is disabled.
-class NoMutex : base::NoCopy {
- public:
- NoMutex(void) {}
- inline void lock(void) {}
- inline bool try_lock(void) {
- return true;
- }
- inline void unlock(void) {}
-};
-/// @brief Lock guard wrapper used when multi-threading is disabled.
-template
-class NoScopedLock : base::NoCopy {
- public:
- explicit NoScopedLock(Mutex&) {
- }
- virtual ~NoScopedLock(void) {
- }
- private:
- NoScopedLock(void);
-};
-} // namespace internal
-typedef base::threading::internal::NoMutex Mutex;
-typedef base::threading::internal::NoScopedLock ScopedLock;
-#endif // ELPP_THREADING_ENABLED
-/// @brief Base of thread safe class, this class is inheritable-only
-class ThreadSafe {
- public:
- virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); }
- virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); }
- virtual inline base::threading::Mutex& lock(void) ELPP_FINAL { return m_mutex; }
- protected:
- ThreadSafe(void) {}
- virtual ~ThreadSafe(void) {}
- private:
- base::threading::Mutex m_mutex;
-};
-
-#if ELPP_THREADING_ENABLED
-# if !ELPP_USE_STD_THREADING
-/// @brief Gets ID of currently running threading in windows systems. On unix, nothing is returned.
-static std::string getCurrentThreadId(void) {
- std::stringstream ss;
-# if (ELPP_OS_WINDOWS)
- ss << GetCurrentThreadId();
-# endif // (ELPP_OS_WINDOWS)
- return ss.str();
-}
-# else
-/// @brief Gets ID of currently running threading using std::this_thread::get_id()
-static std::string getCurrentThreadId(void) {
- std::stringstream ss;
- ss << std::this_thread::get_id();
- return ss.str();
-}
-# endif // !ELPP_USE_STD_THREADING
-#else
-static inline std::string getCurrentThreadId(void) {
- return std::string();
-}
-#endif // ELPP_THREADING_ENABLED
-} // namespace threading
-namespace utils {
-class File : base::StaticClass {
- public:
- /// @brief Creates new out file stream for specified filename.
- /// @return Pointer to newly created fstream or nullptr
- static base::type::fstream_t* newFileStream(const std::string& filename);
-
- /// @brief Gets size of file provided in stream
- static std::size_t getSizeOfFile(base::type::fstream_t* fs);
-
- /// @brief Determines whether or not provided path exist in current file system
- static bool pathExists(const char* path, bool considerFile = false);
-
- /// @brief Creates specified path on file system
- /// @param path Path to create.
- static bool createPath(const std::string& path);
- /// @brief Extracts path of filename with leading slash
- static std::string extractPathFromFilename(const std::string& fullPath,
- const char* separator = base::consts::kFilePathSeparator);
- /// @brief builds stripped filename and puts it in buff
- static void buildStrippedFilename(const char* filename, char buff[],
- std::size_t limit = base::consts::kSourceFilenameMaxLength);
- /// @brief builds base filename and puts it in buff
- static void buildBaseFilename(const std::string& fullPath, char buff[],
- std::size_t limit = base::consts::kSourceFilenameMaxLength,
- const char* separator = base::consts::kFilePathSeparator);
-};
-/// @brief String utilities helper class used internally. You should not use it.
-class Str : base::StaticClass {
- public:
- /// @brief Checks if character is digit. Dont use libc implementation of it to prevent locale issues.
- static inline bool isDigit(char c) {
- return c >= '0' && c <= '9';
- }
-
- /// @brief Matches wildcards, '*' and '?' only supported.
- static bool wildCardMatch(const char* str, const char* pattern);
-
- static std::string& ltrim(std::string& str);
- static std::string& rtrim(std::string& str);
- static std::string& trim(std::string& str);
-
- /// @brief Determines whether or not str starts with specified string
- /// @param str String to check
- /// @param start String to check against
- /// @return Returns true if starts with specified string, false otherwise
- static bool startsWith(const std::string& str, const std::string& start);
-
- /// @brief Determines whether or not str ends with specified string
- /// @param str String to check
- /// @param end String to check against
- /// @return Returns true if ends with specified string, false otherwise
- static bool endsWith(const std::string& str, const std::string& end);
-
- /// @brief Replaces all instances of replaceWhat with 'replaceWith'. Original variable is changed for performance.
- /// @param [in,out] str String to replace from
- /// @param replaceWhat Character to replace
- /// @param replaceWith Character to replace with
- /// @return Modified version of str
- static std::string& replaceAll(std::string& str, char replaceWhat, char replaceWith);
-
- /// @brief Replaces all instances of 'replaceWhat' with 'replaceWith'. (String version) Replaces in place
- /// @param str String to replace from
- /// @param replaceWhat Character to replace
- /// @param replaceWith Character to replace with
- /// @return Modified (original) str
- static std::string& replaceAll(std::string& str, const std::string& replaceWhat,
- const std::string& replaceWith);
-
- static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat,
- const base::type::string_t& replaceWith);
-#if defined(ELPP_UNICODE)
- static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat,
- const std::string& replaceWith);
-#endif // defined(ELPP_UNICODE)
- /// @brief Converts string to uppercase
- /// @param str String to convert
- /// @return Uppercase string
- static std::string& toUpper(std::string& str);
-
- /// @brief Compares cstring equality - uses strcmp
- static bool cStringEq(const char* s1, const char* s2);
-
- /// @brief Compares cstring equality (case-insensitive) - uses toupper(char)
- /// Dont use strcasecmp because of CRT (VC++)
- static bool cStringCaseEq(const char* s1, const char* s2);
-
- /// @brief Returns true if c exist in str
- static bool contains(const char* str, char c);
-
- static char* convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded = true);
- static char* addToBuff(const char* str, char* buf, const char* bufLim);
- static char* clearBuff(char buff[], std::size_t lim);
-
- /// @brief Converts wchar* to char*
- /// NOTE: Need to free return value after use!
- static char* wcharPtrToCharPtr(const wchar_t* line);
-};
-/// @brief Operating System helper static class used internally. You should not use it.
-class OS : base::StaticClass {
- public:
-#if ELPP_OS_WINDOWS
- /// @brief Gets environment variables for Windows based OS.
- /// We are not using getenv(const char*)
because of CRT deprecation
- /// @param varname Variable name to get environment variable value for
- /// @return If variable exist the value of it otherwise nullptr
- static const char* getWindowsEnvironmentVariable(const char* varname);
-#endif // ELPP_OS_WINDOWS
-#if ELPP_OS_ANDROID
- /// @brief Reads android property value
- static std::string getProperty(const char* prop);
-
- /// @brief Reads android device name
- static std::string getDeviceName(void);
-#endif // ELPP_OS_ANDROID
-
- /// @brief Runs command on terminal and returns the output.
- ///
- /// @detail This is applicable only on unix based systems, for all other OS, an empty string is returned.
- /// @param command Bash command
- /// @return Result of bash output or empty string if no result found.
- static const std::string getBashOutput(const char* command);
-
- /// @brief Gets environment variable. This is cross-platform and CRT safe (for VC++)
- /// @param variableName Environment variable name
- /// @param defaultVal If no environment variable or value found the value to return by default
- /// @param alternativeBashCommand If environment variable not found what would be alternative bash command
- /// in order to look for value user is looking for. E.g, for 'user' alternative command will 'whoami'
- static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal,
- const char* alternativeBashCommand = nullptr);
- /// @brief Gets current username.
- static std::string currentUser(void);
-
- /// @brief Gets current host name or computer name.
- ///
- /// @detail For android systems this is device name with its manufacturer and model separated by hyphen
- static std::string currentHost(void);
- /// @brief Whether or not terminal supports colors
- static bool termSupportsColor(void);
-};
-/// @brief Contains utilities for cross-platform date/time. This class make use of el::base::utils::Str
-class DateTime : base::StaticClass {
- public:
- /// @brief Cross platform gettimeofday for Windows and unix platform. This can be used to determine current microsecond.
- ///
- /// @detail For unix system it uses gettimeofday(timeval*, timezone*) and for Windows, a separate implementation is provided
- /// @param [in,out] tv Pointer that gets updated
- static void gettimeofday(struct timeval* tv);
-
- /// @brief Gets current date and time with a subsecond part.
- /// @param format User provided date/time format
- /// @param ssPrec A pointer to base::SubsecondPrecision from configuration (non-null)
- /// @returns string based date time in specified format.
- static std::string getDateTime(const char* format, const base::SubsecondPrecision* ssPrec);
-
- /// @brief Converts timeval (struct from ctime) to string using specified format and subsecond precision
- static std::string timevalToString(struct timeval tval, const char* format,
- const el::base::SubsecondPrecision* ssPrec);
-
- /// @brief Formats time to get unit accordingly, units like second if > 1000 or minutes if > 60000 etc
- static base::type::string_t formatTime(unsigned long long time, base::TimestampUnit timestampUnit);
-
- /// @brief Gets time difference in milli/micro second depending on timestampUnit
- static unsigned long long getTimeDifference(const struct timeval& endTime, const struct timeval& startTime,
- base::TimestampUnit timestampUnit);
-
-
- static struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo);
- private:
- static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo,
- std::size_t msec, const base::SubsecondPrecision* ssPrec);
-};
-/// @brief Command line arguments for application if specified using el::Helpers::setArgs(..) or START_EASYLOGGINGPP(..)
-class CommandLineArgs {
- public:
- CommandLineArgs(void) {
- setArgs(0, static_cast(nullptr));
- }
- CommandLineArgs(int argc, const char** argv) {
- setArgs(argc, argv);
- }
- CommandLineArgs(int argc, char** argv) {
- setArgs(argc, argv);
- }
- virtual ~CommandLineArgs(void) {}
- /// @brief Sets arguments and parses them
- inline void setArgs(int argc, const char** argv) {
- setArgs(argc, const_cast(argv));
- }
- /// @brief Sets arguments and parses them
- void setArgs(int argc, char** argv);
- /// @brief Returns true if arguments contain paramKey with a value (separated by '=')
- bool hasParamWithValue(const char* paramKey) const;
- /// @brief Returns value of arguments
- /// @see hasParamWithValue(const char*)
- const char* getParamValue(const char* paramKey) const;
- /// @brief Return true if arguments has a param (not having a value) i,e without '='
- bool hasParam(const char* paramKey) const;
- /// @brief Returns true if no params available. This exclude argv[0]
- bool empty(void) const;
- /// @brief Returns total number of arguments. This exclude argv[0]
- std::size_t size(void) const;
- friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c);
-
- private:
- int m_argc;
- char** m_argv;
- std::unordered_map m_paramsWithValue;
- std::vector m_params;
-};
-/// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type.
-///
-/// @detail Most of the functions are virtual final methods but anything implementing this abstract class should implement
-/// unregisterAll() and deepCopy(const AbstractRegistry&) and write registerNew() method according to container
-/// and few more methods; get() to find element, unregister() to unregister single entry.
-/// Please note that this is thread-unsafe and should also implement thread-safety mechanisms in implementation.
-template
-class AbstractRegistry : public base::threading::ThreadSafe {
- public:
- typedef typename Container::iterator iterator;
- typedef typename Container::const_iterator const_iterator;
-
- /// @brief Default constructor
- AbstractRegistry(void) {}
-
- /// @brief Move constructor that is useful for base classes
- AbstractRegistry(AbstractRegistry&& sr) {
- if (this == &sr) {
- return;
- }
- unregisterAll();
- m_list = std::move(sr.m_list);
- }
-
- bool operator==(const AbstractRegistry& other) {
- if (size() != other.size()) {
- return false;
- }
- for (std::size_t i = 0; i < m_list.size(); ++i) {
- if (m_list.at(i) != other.m_list.at(i)) {
- return false;
- }
- }
- return true;
- }
-
- bool operator!=(const AbstractRegistry& other) {
- if (size() != other.size()) {
- return true;
- }
- for (std::size_t i = 0; i < m_list.size(); ++i) {
- if (m_list.at(i) != other.m_list.at(i)) {
- return true;
- }
- }
- return false;
- }
-
- /// @brief Assignment move operator
- AbstractRegistry& operator=(AbstractRegistry&& sr) {
- if (this == &sr) {
- return *this;
- }
- unregisterAll();
- m_list = std::move(sr.m_list);
- return *this;
- }
-
- virtual ~AbstractRegistry(void) {
- }
-
- /// @return Iterator pointer from start of repository
- virtual inline iterator begin(void) ELPP_FINAL {
- return m_list.begin();
- }
-
- /// @return Iterator pointer from end of repository
- virtual inline iterator end(void) ELPP_FINAL {
- return m_list.end();
- }
-
-
- /// @return Constant iterator pointer from start of repository
- virtual inline const_iterator cbegin(void) const ELPP_FINAL {
- return m_list.cbegin();
- }
-
- /// @return End of repository
- virtual inline const_iterator cend(void) const ELPP_FINAL {
- return m_list.cend();
- }
-
- /// @return Whether or not repository is empty
- virtual inline bool empty(void) const ELPP_FINAL {
- return m_list.empty();
- }
-
- /// @return Size of repository
- virtual inline std::size_t size(void) const ELPP_FINAL {
- return m_list.size();
- }
-
- /// @brief Returns underlying container by reference
- virtual inline Container& list(void) ELPP_FINAL {
- return m_list;
- }
-
- /// @brief Returns underlying container by constant reference.
- virtual inline const Container& list(void) const ELPP_FINAL {
- return m_list;
- }
-
- /// @brief Unregisters all the pointers from current repository.
- virtual void unregisterAll(void) = 0;
-
- protected:
- virtual void deepCopy(const AbstractRegistry&) = 0;
- void reinitDeepCopy(const AbstractRegistry& sr) {
- unregisterAll();
- deepCopy(sr);
- }
-
- private:
- Container m_list;
-};
-
-/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (non-predicate version)
-///
-/// @detail NOTE: This is thread-unsafe implementation (although it contains lock function, it does not use these functions)
-/// of AbstractRegistry. Any implementation of this class should be
-/// explicitly (by using lock functions)
-template
-class Registry : public AbstractRegistry> {
- public:
- typedef typename Registry::iterator iterator;
- typedef typename Registry::const_iterator const_iterator;
-
- Registry(void) {}
-
- /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor.
- Registry(const Registry& sr) : AbstractRegistry>() {
- if (this == &sr) {
- return;
- }
- this->reinitDeepCopy(sr);
- }
-
- /// @brief Assignment operator that unregisters all the existing registries and deeply copies each of repo element
- /// @see unregisterAll()
- /// @see deepCopy(const AbstractRegistry&)
- Registry& operator=(const Registry& sr) {
- if (this == &sr) {
- return *this;
- }
- this->reinitDeepCopy(sr);
- return *this;
- }
-
- virtual ~Registry(void) {
- unregisterAll();
- }
-
- protected:
- virtual void unregisterAll(void) ELPP_FINAL {
- if (!this->empty()) {
- for (auto&& curr : this->list()) {
- base::utils::safeDelete(curr.second);
- }
- this->list().clear();
- }
- }
-
-/// @brief Registers new registry to repository.
- virtual void registerNew(const T_Key& uniqKey, T_Ptr* ptr) ELPP_FINAL {
- unregister(uniqKey);
- this->list().insert(std::make_pair(uniqKey, ptr));
- }
-
-/// @brief Unregisters single entry mapped to specified unique key
- void unregister(const T_Key& uniqKey) {
- T_Ptr* existing = get(uniqKey);
- if (existing != nullptr) {
- this->list().erase(uniqKey);
- base::utils::safeDelete(existing);
- }
- }
-
-/// @brief Gets pointer from repository. If none found, nullptr is returned.
- T_Ptr* get(const T_Key& uniqKey) {
- iterator it = this->list().find(uniqKey);
- return it == this->list().end()
- ? nullptr
- : it->second;
- }
-
- private:
- virtual void deepCopy(const AbstractRegistry>& sr) ELPP_FINAL {
- for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) {
- registerNew(it->first, new T_Ptr(*it->second));
- }
- }
-};
-
-/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (predicate version)
-///
-/// @detail NOTE: This is thread-unsafe implementation of AbstractRegistry. Any implementation of this class
-/// should be made thread-safe explicitly
-template
-class RegistryWithPred : public AbstractRegistry> {
- public:
- typedef typename RegistryWithPred::iterator iterator;
- typedef typename RegistryWithPred::const_iterator const_iterator;
-
- RegistryWithPred(void) {
- }
-
- virtual ~RegistryWithPred(void) {
- unregisterAll();
- }
-
- /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor.
- RegistryWithPred(const RegistryWithPred& sr) : AbstractRegistry>() {
- if (this == &sr) {
- return;
- }
- this->reinitDeepCopy(sr);
- }
-
- /// @brief Assignment operator that unregisters all the existing registries and deeply copies each of repo element
- /// @see unregisterAll()
- /// @see deepCopy(const AbstractRegistry&)
- RegistryWithPred& operator=(const RegistryWithPred& sr) {
- if (this == &sr) {
- return *this;
- }
- this->reinitDeepCopy(sr);
- return *this;
- }
-
- friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const RegistryWithPred& sr) {
- for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
- os << ELPP_LITERAL(" ") << **it << ELPP_LITERAL("\n");
- }
- return os;
- }
-
- protected:
- virtual void unregisterAll(void) ELPP_FINAL {
- if (!this->empty()) {
- for (auto&& curr : this->list()) {
- base::utils::safeDelete(curr);
- }
- this->list().clear();
- }
- }
-
- virtual void unregister(T_Ptr*& ptr) ELPP_FINAL {
- if (ptr) {
- iterator iter = this->begin();
- for (; iter != this->end(); ++iter) {
- if (ptr == *iter) {
- break;
- }
- }
- if (iter != this->end() && *iter != nullptr) {
- this->list().erase(iter);
- base::utils::safeDelete(*iter);
- }
- }
- }
-
- virtual inline void registerNew(T_Ptr* ptr) ELPP_FINAL {
- this->list().push_back(ptr);
- }
-
-/// @brief Gets pointer from repository with specified arguments. Arguments are passed to predicate
-/// in order to validate pointer.
- template
- T_Ptr* get(const T& arg1, const T2 arg2) {
- iterator iter = std::find_if(this->list().begin(), this->list().end(), Pred(arg1, arg2));
- if (iter != this->list().end() && *iter != nullptr) {
- return *iter;
- }
- return nullptr;
- }
-
- private:
- virtual void deepCopy(const AbstractRegistry>& sr) {
- for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
- registerNew(new T_Ptr(**it));
- }
- }
-};
-class Utils {
- public:
- template
- static bool installCallback(const std::string& id, std::unordered_map* mapT) {
- if (mapT->find(id) == mapT->end()) {
- mapT->insert(std::make_pair(id, TPtr(new T())));
- return true;
- }
- return false;
- }
-
- template
- static void uninstallCallback(const std::string& id, std::unordered_map* mapT) {
- if (mapT->find(id) != mapT->end()) {
- mapT->erase(id);
- }
- }
-
- template
- static T* callback(const std::string& id, std::unordered_map* mapT) {
- typename std::unordered_map::iterator iter = mapT->find(id);
- if (iter != mapT->end()) {
- return static_cast(iter->second.get());
- }
- return nullptr;
- }
-};
-} // namespace utils
-} // namespace base
-/// @brief Base of Easylogging++ friendly class
-///
-/// @detail After inheriting this class publicly, implement pure-virtual function `void log(std::ostream&) const`
-class Loggable {
- public:
- virtual ~Loggable(void) {}
- virtual void log(el::base::type::ostream_t&) const = 0;
- private:
- friend inline el::base::type::ostream_t& operator<<(el::base::type::ostream_t& os, const Loggable& loggable) {
- loggable.log(os);
- return os;
- }
-};
-namespace base {
-/// @brief Represents log format containing flags and date format. This is used internally to start initial log
-class LogFormat : public Loggable {
- public:
- LogFormat(void);
- LogFormat(Level level, const base::type::string_t& format);
- LogFormat(const LogFormat& logFormat);
- LogFormat(LogFormat&& logFormat);
- LogFormat& operator=(const LogFormat& logFormat);
- virtual ~LogFormat(void) {}
- bool operator==(const LogFormat& other);
-
- /// @brief Updates format to be used while logging.
- /// @param userFormat User provided format
- void parseFromFormat(const base::type::string_t& userFormat);
-
- inline Level level(void) const {
- return m_level;
- }
-
- inline const base::type::string_t& userFormat(void) const {
- return m_userFormat;
- }
-
- inline const base::type::string_t& format(void) const {
- return m_format;
- }
-
- inline const std::string& dateTimeFormat(void) const {
- return m_dateTimeFormat;
- }
-
- inline base::type::EnumType flags(void) const {
- return m_flags;
- }
-
- inline bool hasFlag(base::FormatFlags flag) const {
- return base::utils::hasFlag(flag, m_flags);
- }
-
- virtual void log(el::base::type::ostream_t& os) const {
- os << m_format;
- }
-
- protected:
- /// @brief Updates date time format if available in currFormat.
- /// @param index Index where %datetime, %date or %time was found
- /// @param [in,out] currFormat current format that is being used to format
- virtual void updateDateFormat(std::size_t index, base::type::string_t& currFormat) ELPP_FINAL;
-
- /// @brief Updates %level from format. This is so that we dont have to do it at log-writing-time. It uses m_format and m_level
- virtual void updateFormatSpec(void) ELPP_FINAL;
-
- inline void addFlag(base::FormatFlags flag) {
- base::utils::addFlag(flag, &m_flags);
- }
-
- private:
- Level m_level;
- base::type::string_t m_userFormat;
- base::type::string_t m_format;
- std::string m_dateTimeFormat;
- base::type::EnumType m_flags;
- std::string m_currentUser;
- std::string m_currentHost;
- friend class el::Logger; // To resolve loggerId format specifier easily
-};
-} // namespace base
-/// @brief Resolving function for format specifier
-typedef std::function FormatSpecifierValueResolver;
-/// @brief User-provided custom format specifier
-/// @see el::Helpers::installCustomFormatSpecifier
-/// @see FormatSpecifierValueResolver
-class CustomFormatSpecifier {
- public:
- CustomFormatSpecifier(const char* formatSpecifier, const FormatSpecifierValueResolver& resolver) :
- m_formatSpecifier(formatSpecifier), m_resolver(resolver) {}
- inline const char* formatSpecifier(void) const {
- return m_formatSpecifier;
- }
- inline const FormatSpecifierValueResolver& resolver(void) const {
- return m_resolver;
- }
- inline bool operator==(const char* formatSpecifier) {
- return strcmp(m_formatSpecifier, formatSpecifier) == 0;
- }
-
- private:
- const char* m_formatSpecifier;
- FormatSpecifierValueResolver m_resolver;
-};
-/// @brief Represents single configuration that has representing level, configuration type and a string based value.
-///
-/// @detail String based value means any value either its boolean, integer or string itself, it will be embedded inside quotes
-/// and will be parsed later.
-///
-/// Consider some examples below:
-/// * el::Configuration confEnabledInfo(el::Level::Info, el::ConfigurationType::Enabled, "true");
-/// * el::Configuration confMaxLogFileSizeInfo(el::Level::Info, el::ConfigurationType::MaxLogFileSize, "2048");
-/// * el::Configuration confFilenameInfo(el::Level::Info, el::ConfigurationType::Filename, "/var/log/my.log");
-class Configuration : public Loggable {
- public:
- Configuration(const Configuration& c);
- Configuration& operator=(const Configuration& c);
-
- virtual ~Configuration(void) {
- }
-
- /// @brief Full constructor used to sets value of configuration
- Configuration(Level level, ConfigurationType configurationType, const std::string& value);
-
- /// @brief Gets level of current configuration
- inline Level level(void) const {
- return m_level;
- }
-
- /// @brief Gets configuration type of current configuration
- inline ConfigurationType configurationType(void) const {
- return m_configurationType;
- }
-
- /// @brief Gets string based configuration value
- inline const std::string& value(void) const {
- return m_value;
- }
-
- /// @brief Set string based configuration value
- /// @param value Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values
- /// use them in quotes. They will be parsed when configuring
- inline void setValue(const std::string& value) {
- m_value = value;
- }
-
- virtual void log(el::base::type::ostream_t& os) const;
-
- /// @brief Used to find configuration from configuration (pointers) repository. Avoid using it.
- class Predicate {
- public:
- Predicate(Level level, ConfigurationType configurationType);
-
- bool operator()(const Configuration* conf) const;
-
- private:
- Level m_level;
- ConfigurationType m_configurationType;
- };
-
- private:
- Level m_level;
- ConfigurationType m_configurationType;
- std::string m_value;
-};
-
-/// @brief Thread-safe Configuration repository
-///
-/// @detail This repository represents configurations for all the levels and configuration type mapped to a value.
-class Configurations : public base::utils::RegistryWithPred {
- public:
- /// @brief Default constructor with empty repository
- Configurations(void);
-
- /// @brief Constructor used to set configurations using configuration file.
- /// @param configurationFile Full path to configuration file
- /// @param useDefaultsForRemaining Lets you set the remaining configurations to default.
- /// @param base If provided, this configuration will be based off existing repository that this argument is pointing to.
- /// @see parseFromFile(const std::string&, Configurations* base)
- /// @see setRemainingToDefault()
- Configurations(const std::string& configurationFile, bool useDefaultsForRemaining = true,
- Configurations* base = nullptr);
-
- virtual ~Configurations(void) {
- }
-
- /// @brief Parses configuration from file.
- /// @param configurationFile Full path to configuration file
- /// @param base Configurations to base new configuration repository off. This value is used when you want to use
- /// existing Configurations to base all the values and then set rest of configuration via configuration file.
- /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
- /// do not proceed without successful parse.
- bool parseFromFile(const std::string& configurationFile, Configurations* base = nullptr);
-
- /// @brief Parse configurations from configuration string.
- ///
- /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary
- /// new line characters are provided.
- /// @param base Configurations to base new configuration repository off. This value is used when you want to use
- /// existing Configurations to base all the values and then set rest of configuration via configuration text.
- /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
- /// do not proceed without successful parse.
- bool parseFromText(const std::string& configurationsString, Configurations* base = nullptr);
-
- /// @brief Sets configuration based-off an existing configurations.
- /// @param base Pointer to existing configurations.
- void setFromBase(Configurations* base);
-
- /// @brief Determines whether or not specified configuration type exists in the repository.
- ///
- /// @detail Returns as soon as first level is found.
- /// @param configurationType Type of configuration to check existence for.
- bool hasConfiguration(ConfigurationType configurationType);
-
- /// @brief Determines whether or not specified configuration type exists for specified level
- /// @param level Level to check
- /// @param configurationType Type of configuration to check existence for.
- bool hasConfiguration(Level level, ConfigurationType configurationType);
-
- /// @brief Sets value of configuration for specified level.
- ///
- /// @detail Any existing configuration for specified level will be replaced. Also note that configuration types
- /// ConfigurationType::SubsecondPrecision and ConfigurationType::PerformanceTracking will be ignored if not set for
- /// Level::Global because these configurations are not dependant on level.
- /// @param level Level to set configuration for (el::Level).
- /// @param configurationType Type of configuration (el::ConfigurationType)
- /// @param value A string based value. Regardless of what the data type of configuration is, it will always be string
- /// from users' point of view. This is then parsed later to be used internally.
- /// @see Configuration::setValue(const std::string& value)
- /// @see el::Level
- /// @see el::ConfigurationType
- void set(Level level, ConfigurationType configurationType, const std::string& value);
-
- /// @brief Sets single configuration based on other single configuration.
- /// @see set(Level level, ConfigurationType configurationType, const std::string& value)
- void set(Configuration* conf);
-
- inline Configuration* get(Level level, ConfigurationType configurationType) {
- base::threading::ScopedLock scopedLock(lock());
- return RegistryWithPred::get(level, configurationType);
- }
-
- /// @brief Sets configuration for all levels.
- /// @param configurationType Type of configuration
- /// @param value String based value
- /// @see Configurations::set(Level level, ConfigurationType configurationType, const std::string& value)
- inline void setGlobally(ConfigurationType configurationType, const std::string& value) {
- setGlobally(configurationType, value, false);
- }
-
- /// @brief Clears repository so that all the configurations are unset
- inline void clear(void) {
- base::threading::ScopedLock scopedLock(lock());
- unregisterAll();
- }
-
- /// @brief Gets configuration file used in parsing this configurations.
- ///
- /// @detail If this repository was set manually or by text this returns empty string.
- inline const std::string& configurationFile(void) const {
- return m_configurationFile;
- }
-
- /// @brief Sets configurations to "factory based" configurations.
- void setToDefault(void);
-
- /// @brief Lets you set the remaining configurations to default.
- ///
- /// @detail By remaining, it means that the level/type a configuration does not exist for.
- /// This function is useful when you want to minimize chances of failures, e.g, if you have a configuration file that sets
- /// configuration for all the configurations except for Enabled or not, we use this so that ENABLED is set to default i.e,
- /// true. If you dont do this explicitly (either by calling this function or by using second param in Constructor
- /// and try to access a value, an error is thrown
- void setRemainingToDefault(void);
-
- /// @brief Parser used internally to parse configurations from file or text.
- ///
- /// @detail This class makes use of base::utils::Str.
- /// You should not need this unless you are working on some tool for Easylogging++
- class Parser : base::StaticClass {
- public:
- /// @brief Parses configuration from file.
- /// @param configurationFile Full path to configuration file
- /// @param sender Sender configurations pointer. Usually 'this' is used from calling class
- /// @param base Configurations to base new configuration repository off. This value is used when you want to use
- /// existing Configurations to base all the values and then set rest of configuration via configuration file.
- /// @return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you
- /// do not proceed without successful parse.
- static bool parseFromFile(const std::string& configurationFile, Configurations* sender,
- Configurations* base = nullptr);
-
- /// @brief Parse configurations from configuration string.
- ///
- /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary
- /// new line characters are provided. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you
- /// do not proceed without successful parse (This is recommended)
- /// @param configurationsString the configuration in plain text format
- /// @param sender Sender configurations pointer. Usually 'this' is used from calling class
- /// @param base Configurations to base new configuration repository off. This value is used when you want to use
- /// existing Configurations to base all the values and then set rest of configuration via configuration text.
- /// @return True if successfully parsed, false otherwise.
- static bool parseFromText(const std::string& configurationsString, Configurations* sender,
- Configurations* base = nullptr);
-
- private:
- friend class el::Loggers;
- static void ignoreComments(std::string* line);
- static bool isLevel(const std::string& line);
- static bool isComment(const std::string& line);
- static inline bool isConfig(const std::string& line);
- static bool parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, Level* currLevel,
- Configurations* conf);
- };
-
- private:
- std::string m_configurationFile;
- bool m_isFromFile;
- friend class el::Loggers;
-
- /// @brief Unsafely sets configuration if does not already exist
- void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value);
-
- /// @brief Thread unsafe set
- void unsafeSet(Level level, ConfigurationType configurationType, const std::string& value);
-
- /// @brief Sets configurations for all levels including Level::Global if includeGlobalLevel is true
- /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value)
- void setGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel);
-
- /// @brief Sets configurations (Unsafely) for all levels including Level::Global if includeGlobalLevel is true
- /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value)
- void unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel);
-};
-
-namespace base {
-typedef std::shared_ptr FileStreamPtr;
-typedef std::unordered_map LogStreamsReferenceMap;
-typedef std::shared_ptr LogStreamsReferenceMapPtr;
-/// @brief Configurations with data types.
-///
-/// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations.
-/// This is to perform faster while writing logs using correct configurations.
-///
-/// This is thread safe and final class containing non-virtual destructor (means nothing should inherit this class)
-class TypedConfigurations : public base::threading::ThreadSafe {
- public:
- /// @brief Constructor to initialize (construct) the object off el::Configurations
- /// @param configurations Configurations pointer/reference to base this typed configurations off.
- /// @param logStreamsReference Use ELPP->registeredLoggers()->logStreamsReference()
- TypedConfigurations(Configurations* configurations, LogStreamsReferenceMapPtr logStreamsReference);
-
- TypedConfigurations(const TypedConfigurations& other);
-
- virtual ~TypedConfigurations(void) {
- }
-
- const Configurations* configurations(void) const {
- return m_configurations;
- }
-
- bool enabled(Level level);
- bool toFile(Level level);
- const std::string& filename(Level level);
- bool toStandardOutput(Level level);
- const base::LogFormat& logFormat(Level level);
- const base::SubsecondPrecision& subsecondPrecision(Level level = Level::Global);
- const base::MillisecondsWidth& millisecondsWidth(Level level = Level::Global);
- bool performanceTracking(Level level = Level::Global);
- base::type::fstream_t* fileStream(Level level);
- std::size_t maxLogFileSize(Level level);
- std::size_t logFlushThreshold(Level level);
-
- private:
- Configurations* m_configurations;
- std::unordered_map m_enabledMap;
- std::unordered_map m_toFileMap;
- std::unordered_map m_filenameMap;
- std::unordered_map m_toStandardOutputMap;
- std::unordered_map m_logFormatMap;
- std::unordered_map m_subsecondPrecisionMap;
- std::unordered_map m_performanceTrackingMap;
- std::unordered_map m_fileStreamMap;
- std::unordered_map m_maxLogFileSizeMap;
- std::unordered_map m_logFlushThresholdMap;
- LogStreamsReferenceMapPtr m_logStreamsReference = nullptr;
-
- friend class el::Helpers;
- friend class el::base::MessageBuilder;
- friend class el::base::Writer;
- friend class el::base::DefaultLogDispatchCallback;
- friend class el::base::LogDispatcher;
-
- template
- inline Conf_T getConfigByVal(Level level, const std::unordered_map* confMap, const char* confName) {
- base::threading::ScopedLock scopedLock(lock());
- return unsafeGetConfigByVal(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope
- }
-
- template
- inline Conf_T& getConfigByRef(Level level, std::unordered_map* confMap, const char* confName) {
- base::threading::ScopedLock scopedLock(lock());
- return unsafeGetConfigByRef(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope
- }
-
- template
- Conf_T unsafeGetConfigByVal(Level level, const std::unordered_map