From 251daa2e074905c3cab1836e28655d76b5449ff1 Mon Sep 17 00:00:00 2001 From: Majid Date: Fri, 23 Feb 2018 17:06:51 +1100 Subject: [PATCH 1/2] Two loggers writing to same file is undefined behaviour #613 --- CHANGELOG.md | 4 +++ samples/STL/multi-loggers-to-same-file.cpp | 39 ++++++++++++++++++++++ samples/default-logger.conf | 2 +- src/easylogging++.cc | 22 ++++++++++++ src/easylogging++.h | 9 +++-- 5 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 samples/STL/multi-loggers-to-same-file.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index df68c5db3..c3de6e34d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## [9.96.1] - 23-02-2018 +### Fixes +- Two loggers writing to same file is undefined behaviour #613 + ## [9.96.0] - 14-02-2018 ### Fixes - Potential deadlocks in extreme edge case #609 diff --git a/samples/STL/multi-loggers-to-same-file.cpp b/samples/STL/multi-loggers-to-same-file.cpp new file mode 100644 index 000000000..c29f28b00 --- /dev/null +++ b/samples/STL/multi-loggers-to-same-file.cpp @@ -0,0 +1,39 @@ +// +// This file is part of Easylogging++ samples +// +// Revision 1.0 +// + +#include +#include "easylogging++.h" + +INITIALIZE_EASYLOGGINGPP + +void def() { + for (int i = 0; i < 10000; ++i) + CLOG(INFO, "first") << "This is from first " << i; +} + +void second() { + for (int i = 0; i < 10000; ++i) + CLOG(INFO, "second") << "This is from second" << i; +} + +int main(int,char**){ + el::Loggers::addFlag(el::LoggingFlag::CreateLoggerAutomatically); + + el::Configurations confFromFile("../default-logger.conf"); + + el::Loggers::setDefaultConfigurations(confFromFile, true); + + LOG(INFO)<<"The program has started!"; + + std::thread t1(def); + std::thread t2(second); + + t1.join(); + t2.join(); + + LOG(INFO) << "Shutting down."; + return 0; +} diff --git a/samples/default-logger.conf b/samples/default-logger.conf index 396a59b4b..9e34afd2c 100644 --- a/samples/default-logger.conf +++ b/samples/default-logger.conf @@ -1,5 +1,5 @@ * GLOBAL: - FORMAT = "%datetime | %level | %msg" + FORMAT = "%datetime | %level | %logger | %msg" FILENAME = "/tmp/logs/myeasylog-configuration.cpp.log" ENABLED = true TO_FILE = true diff --git a/src/easylogging++.cc b/src/easylogging++.cc index c58a733d0..122e92ee1 100644 --- a/src/easylogging++.cc +++ b/src/easylogging++.cc @@ -2096,9 +2096,31 @@ void Storage::setApplicationArguments(int argc, char** argv) { #endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG) } +} // namespace base + +// LogDispatchCallback +void LogDispatchCallback::handle(const LogDispatchData* data) { +#if defined(ELPP_THREAD_SAFE) + base::threading::ScopedLock scopedLock(m_fileLocksMapLock); + std::string filename = data->logMessage()->logger()->typedConfigurations()->filename(data->logMessage()->level()); + auto lock = m_fileLocks.find(filename); + if (lock == m_fileLocks.end()) { + m_fileLocks.emplace(std::make_pair(filename, new base::threading::Mutex)); + } +#endif +} + +base::threading::Mutex& LogDispatchCallback::fileHandle(const LogDispatchData* data) { + auto it = m_fileLocks.find(data->logMessage()->logger()->typedConfigurations()->filename(data->logMessage()->level())); + return *(it->second.get()); +} + +namespace base { // DefaultLogDispatchCallback void DefaultLogDispatchCallback::handle(const LogDispatchData* data) { + LogDispatchCallback::handle(data); + base::threading::ScopedLock scopedLock(fileHandle(data)); m_data = data; dispatch(m_data->logMessage()->logger()->logBuilder()->build(m_data->logMessage(), m_data->dispatchAction() == base::DispatchAction::NormalLog)); diff --git a/src/easylogging++.h b/src/easylogging++.h index 8a54ab0d5..3319bc4c1 100644 --- a/src/easylogging++.h +++ b/src/easylogging++.h @@ -380,6 +380,7 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre #include #include #include +#include #include #include #include @@ -417,9 +418,6 @@ ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStre # if defined(ELPP_LOG_STD_ARRAY) # include # endif // defined(ELPP_LOG_STD_ARRAY) -# if defined(ELPP_LOG_UNORDERED_MAP) -# include -# endif // defined(ELPP_LOG_UNORDERED_MAP) # if defined(ELPP_LOG_UNORDERED_SET) # include # endif // defined(ELPP_UNORDERED_SET) @@ -2238,8 +2236,13 @@ class LogDispatchData { } }; class LogDispatchCallback : public Callback { + protected: + virtual void handle(const LogDispatchData* data); + base::threading::Mutex& fileHandle(const LogDispatchData* data); private: friend class base::LogDispatcher; + std::unordered_map> m_fileLocks; + base::threading::Mutex m_fileLocksMapLock; }; class PerformanceTrackingCallback : public Callback { private: From ac1a71c339d20473982748f86f24ab0d3da1cd51 Mon Sep 17 00:00:00 2001 From: Majid Date: Fri, 23 Feb 2018 17:08:52 +1100 Subject: [PATCH 2/2] 9.96.1 release --- CMakeLists.txt | 2 +- README.md | 4 ++-- src/easylogging++.cc | 6 +++--- src/easylogging++.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e422a0baf..954012fb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,7 +27,7 @@ option(lib_utc_datetime "Build library with UTC date/time logging" OFF) set(ELPP_MAJOR_VERSION "9") set(ELPP_MINOR_VERSION "96") -set(ELPP_PATCH_VERSION "0") +set(ELPP_PATCH_VERSION "1") set(ELPP_VERSION_STRING "${ELPP_MAJOR_VERSION}.${ELPP_MINOR_VERSION}.${ELPP_PATCH_VERSION}") set(ELPP_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "The directory the headers are installed in") diff --git a/README.md b/README.md index 2a4ff9655..30b24c4c5 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ![banner] -> **Manual For v9.96.0** +> **Manual For v9.96.1** [![Build Status (Master)](https://img.shields.io/travis/muflihun/easyloggingpp/master.svg)](https://travis-ci.org/muflihun/easyloggingpp) [![Build Status (Develop)](https://img.shields.io/travis/muflihun/easyloggingpp/develop.svg)](https://travis-ci.org/muflihun/easyloggingpp) [![Version](https://img.shields.io/github/release/muflihun/easyloggingpp.svg)](https://github.com/muflihun/easyloggingpp/releases/latest) @@ -100,7 +100,7 @@ # Overview Easylogging++ is single header efficient logging library for C++ applications. It is extremely powerful, highly extendable and configurable to user's requirements. It provides ability to [write your own _sinks_](/samples/send-to-network) (via featured referred as `LogDispatchCallback`). This library is currently used by [hundreds of open-source projects on github](https://github.com/search?q=%22easylogging%2B%2B.h%22&type=Code&utf8=%E2%9C%93) and other open-source source control management sites. -This manual is for Easylogging++ v9.96.0. For other versions please refer to corresponding [release](https://github.com/muflihun/easyloggingpp/releases) on github. +This manual is for Easylogging++ v9.96.1. For other versions please refer to corresponding [release](https://github.com/muflihun/easyloggingpp/releases) on github. > You may also be interested in [Residue](https://github.com/muflihun/residue/) logging server. diff --git a/src/easylogging++.cc b/src/easylogging++.cc index 122e92ee1..bb98e568d 100644 --- a/src/easylogging++.cc +++ b/src/easylogging++.cc @@ -1,7 +1,7 @@ // // Bismillah ar-Rahmaan ar-Raheem // -// Easylogging++ v9.96.0 +// Easylogging++ v9.96.1 // Cross-platform logging library for C++ applications // // Copyright (c) 2012-2018 Muflihun Labs @@ -3004,11 +3004,11 @@ void Loggers::clearVModules(void) { // VersionInfo const std::string VersionInfo::version(void) { - return std::string("9.96.0"); + return std::string("9.96.1"); } /// @brief Release date of current version const std::string VersionInfo::releaseDate(void) { - return std::string("14-02-2018 1629hrs"); + return std::string("23-02-2018 1708hrs"); } } // namespace el diff --git a/src/easylogging++.h b/src/easylogging++.h index 3319bc4c1..acffe28cd 100644 --- a/src/easylogging++.h +++ b/src/easylogging++.h @@ -1,7 +1,7 @@ // // Bismillah ar-Rahmaan ar-Raheem // -// Easylogging++ v9.96.0 +// Easylogging++ v9.96.1 // Single-header only, cross-platform logging library for C++ applications // // Copyright (c) 2012-2018 Muflihun Labs