I introduced EasyLogging++ before. This article will build on that to show how to rotate the logs daily.
In a nutshell, assuming your log filename already has date specifiers in it, all you have to do is run these two lines, at midnight each day:
auto L = el::Loggers::getLogger("default");
L->reconfigure();
If you have multiple loggers, repeat that for all of them.
I recommend using a config file to configure EasyLogging++; but if you are configuring it completely in your code, and your FILENAME entry does not include date specifiers, you can instead change the filename at any time with this:
Loggers::reconfigureAllLoggers(
ConfigurationType::Filename,
"/path/to/logs/my-new-filename.log"
);
But, going back to the first approach, here is a complete program to show creating a new log file every 20 seconds (!). First create a logging.conf file with these contents:
-- default
* GLOBAL:
FORMAT = "%datetime{%Y-%M-%d %H:%m:%s.%g},%level,%thread,%msg"
Milliseconds_Width = 4
TO_FILE = true
FILENAME = "info.%datetime{%Y%M%d_%H%m%s}.log"
LOG_FLUSH_THRESHOLD = 5
(The FORMAT
, and Milliseconds_Width
lines are optional, but useful for checking it worked.)
Here is the full code:
#define _ELPP_THREAD_SAFE
#define _ELPP_NO_DEFAULT_LOG_FILE
#include "easylogging++.h"
_INITIALIZE_EASYLOGGINGPP
namespace sc = std::chrono;
int main(int,char**){
el::Loggers::configureFromGlobal("logging.conf");
LOG(INFO)<<"The program has started!";
std::thread logRotatorThread([](){
const sc::seconds wakeUpDelta = sc::seconds(20);
auto nextWakeUp = sc::system_clock::now() + wakeUpDelta;
while(true){
std::this_thread::sleep_until(nextWakeUp);
nextWakeUp += wakeUpDelta;
LOG(INFO) << "About to rotate log file!";
auto L = el::Loggers::getLogger("default");
if(L == nullptr)LOG(ERROR)<<"Oops, it is not called default!";
else L->reconfigure();
}
});
logRotatorThread.detach();
//Main thread
for(int n=0; n < 1000; ++n){
LOG(TRACE) << n;
std::this_thread::sleep_for(sc::milliseconds(100));
}
LOG(INFO) << "Shutting down.";
return 0;
}
I compiled it with this command:
g++ -std=c++11 -Wall -Werror logtest.cpp -lpthread -o logtest
and then ran it with this command:
./logtest
It should be easy to follow. I set up a dedicated thread to call reconfigure()
every 20 seconds, and then the main thread logs a counter about 10 times/second.
You’ll end up with about 5 log files, and you can examine them to see that no log commands were lost.
If I was coding for a mission-critical application, where missing even a single log line would be considered Very Bad, I might set up a mutex and a lock to make sure the main thread is not active when the call to reconfigure()
happens. I don’t know for sure if that is needed, or if it is guaranteed to be safe. If you know for sure one way or the other, please leave a comment!
But, for a once/day log rotation, in most applications this is a small enough risk that I would not want the overhead of the extra mutex, and I would go with the code shown above.