0

I want to write to log file with timestamp. The timestamp should represent the time interval from beginning of the application like below:

1: This log message arrived after 1s of starting the application

5: This log message arrived after 5s of starting the application

Then i want to read the log message in that exact time interval. Like after 1s i will read the first message then when 5s is passed i will read the second message.

Is there any library by which i can do that? I have found some library like easyloggingcpp which can save log file using timestamp. But the timestamp is the corresponding time. Also i have not found any way how to read the message on specific time interval.

Is there any way i can do it?

Community
  • 1
  • 1
Mahmudur Rahman
  • 640
  • 1
  • 6
  • 23
  • 2
    You could simply count seconds yourself with std::chrono and then check inside a loop, if your program is written like that. Alternatively, you can spawn a second thread and use std::this_thread::sleep_for(...) and sleep it for some intervals, that way you don't have an empty while loop running on your CPU. Depends on what exactly you're trying to do. – Qubit May 28 '18 at 07:50
  • I really cannot understand what you are trying to achieve. It is trivial to store startup time in log instance variable, and then use it to know the delta and show it in log file. But what means *I want to read the log message in that exact time interval*? Do you want to read it as soon as written, or do you know in advance at what time it will be written? or whatever? – Serge Ballesta May 28 '18 at 08:24
  • First i want to write it to some file. Then again from some other app/class i want to read the log file. I need to send the log to others after that exact interval from the starting that's why i need to read it in that specific time from the start. @SergeBallesta – Mahmudur Rahman May 28 '18 at 08:28
  • There are 2 different problems here. One is how to know what time have elapsed since beginning of program when writing a log message, and I have already said, it is trivial to do. One is how to have an alternate application read the log message as soon as it has been written. The correct solution of that latter one will depend on the involved OS and on the number of producers and consumers for the log file. You must say more about the context to get more help. – Serge Ballesta May 28 '18 at 08:49
  • The whole file will be written before it is opened for reading & there will be only one consumer to read the file. The alternate application will start only after the file writing is finished @SergeBallesta – Mahmudur Rahman May 28 '18 at 08:52
  • @MahmudurRahman: So you want the reader to wait between the processing of 2 consecutive messages exactly the time that separated them when they were written. Right? – Serge Ballesta May 28 '18 at 09:05
  • @SergeBallesta yes. – Mahmudur Rahman May 28 '18 at 09:06

4 Answers4

1

Global variables are guaranteed to be initialized before main is run.

So first create a global const variable app_start_time initialized with the value

 const auto app_start_time = std::chrono::system_clock::now();

Then in the log function use following code to calculate seconds :

auto time_since_start = std::chrono::system_clock::now() - app_start_time;
auto seconds_since_start= std::chrono::seconds(time_since_start).count();
Robert Andrzejuk
  • 5,076
  • 2
  • 22
  • 31
1

You can use std::chrono library for time purpose. You basically get the time at the beginning of the code and save it in a variable. After that, you can get the current time when ever you need the time interval and find the difference between previous and current time like following.

#include <iostream>
#include <chrono>
#include <ctime>


int main()
{
    auto start = std::chrono::system_clock::now();

    // Some time consuming operations ... 

    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end-start;   
    std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";

    // Some another time consuming operations ... 

    auto end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end-start;   
    std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";

}

For the log messaging, it is just about writing to a file. So you can create your custom Logger class and write a parser specific to it in order to read messages on specific time interval. Another option would be using easyloggingcpp as you said. You can find specific example here

eneski
  • 1,575
  • 17
  • 40
  • How to read the log file on time interval? The idea @Qubit suggested in the comment to use std::this_thread::sleep_for(...) seems like a good idea to me. But is there any other way? – Mahmudur Rahman May 28 '18 at 08:29
  • That might be an option but I don't think that you need a thread. Honestly, this depends on your design. I would prefer to write a small class and send the time from my driver method to write/read messages. I might be able to edit my answer later. – eneski May 28 '18 at 08:45
1

I have simple demo app for this. I use ctime for get timestamp std::time(0). this code should not be reused, it use simple queue (not thread-safe) just for make it simple demo.

#include <iostream>     // std::cout
#include <thread>       // std::thread
#include <cstdio>       // printf, scanf, puts, NULL
#include <cstdlib>      // srand, rand
#include <ctime>        // time
#include <chrono>       // std::chrono::seconds, std::this_thread::sleep_for
#include <queue>        // std::ueue

std::queue<int> queue;

void producer() {
  srand(time(NULL));

  while (1) {
    int message = rand();
    queue.push(message);

    int sleep = rand() % 5;
    std::this_thread::sleep_for(std::chrono::seconds(sleep));
  }
}

void consumer()
{
  int start_time = std::time(0);

  while(1) {

    printf("waiting\n");

    while (queue.empty()); // busy waiting

    int timestamp = std::time(0);
    int message = queue.front();
    int arrival_time_from_start = (timestamp - start_time);

    queue.pop();
    printf("message %d arrive at %d (unix timestamp), %d second after app start.\n", message, timestamp, arrival_time_from_start);

  }  
}

int main() 
{
  std::thread first(producer);
  std::thread second(consumer);

  first.join();                // pauses until first finishes
  second.join();               // pauses until second finishes

  return 0;
}

Producer thread produce some integer to queue, then wait for random second [0-5]. Then the consumer thread, wait for queue filled. When queue filled, it consume (queue.pop()) and print to screen with its unix timestamp (seconds since 01-Jan-1970).

it will produce something like this:

waiting
message 1611033160 arrive at 1527496314 (unix timestamp), 0 second after app start.
waiting
message 1055908354 arrive at 1527496318 (unix timestamp), 4 second after app start.
waiting
message 788236843 arrive at 1527496320 (unix timestamp), 6 second after app start.
waiting
message 1849353197 arrive at 1527496323 (unix timestamp), 9 second after app start.
waiting
message 62004690 arrive at 1527496326 (unix timestamp), 12 second after app start.
waiting
message 1668815337 arrive at 1527496326 (unix timestamp), 12 second after app start.
waiting
message 533376047 arrive at 1527496330 (unix timestamp), 16 second after app start.
ibrohimislam
  • 717
  • 7
  • 21
1

So you need a logging class in producer that will be aware of application start time.

class Logger {
    static std::chrono::steady_clock::time_point start; // program start
    std::ofstream out;                                  // log file stream
public:
    Logger(const char *filename): out(filename) {}
    void log(const char *msg) {                         // log function
        std::chrono::steady_clock::time_point cur = std::chrono::steady_clock::now();
        std::chrono::duration<double> d = cur - start;  // delta time since program start
        // prepend text message with delta time
        out << int(d.count()) << " - " << msg << std::endl;
    }
    ~Logger() {
        out.close();
    }
};

The following part is a One Definition Rule definition that shall occur exactly once in your program. You should write it in the main source even if the definition of the class is in an include file

// definition of static member
std::chrono::steady_clock::time_point Logger::start = std::chrono::steady_clock::now();

You can use it simply in producer program:

int main() {
    Logger log("foo.log");
    std::chrono::duration<int> d = std::chrono::duration<int>(1);
    // sleep for 1 second
    std::this_thread::sleep_for(d);
    log.log("After 1s");
    // sleep for 4 seconds more
    d = std::chrono::duration<int>(4);
    std::this_thread::sleep_for(d);
    log.log("After 5s");
    return 0;
}

Then you need a reader that reads each line from the log file, extracts the delay from beginning and computes a delay from the last message (the delays from beginning are increasing by construction), and sleeps for that time:

int main() {
    std::ifstream in("foo.log");           // log file input stream
    // store program start time
    std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
    std::string line;
    while (std::getline(in, line)) {       // read log file one line at a time
        std::stringstream ss(line);        // parse line to extract delay
        int delay;
        if (! (ss >> delay)) break;
        std::chrono::duration<int> d(delay);
        std::this_thread::sleep_until(start + d); // wait until approriate time
        // message processing (here simple display on stdout)
        std::cout << line << std::endl;
    }
    return 0;
}
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252