Skip to content

Commit 342b52f

Browse files
authored
Merge pull request #3175 from elandini84/feature/yarpmanager/error_time_stamp
Feature: `yarpmanager` log messages time stamp
2 parents 46693e5 + 5ca69ce commit 342b52f

File tree

8 files changed

+195
-13
lines changed

8 files changed

+195
-13
lines changed

doc/release/master.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Fixes
2929
New Features
3030
------------
3131

32-
### devices
32+
### devices
3333

3434
#### multiplenalogsensorremapper
3535

@@ -42,6 +42,10 @@ New Features
4242

4343
* `yarpopencvdisplay` is now able to display a `yarp::sig::LayeredImage`
4444

45+
#### `yarpmanager`
46+
* Added time info to `libYARP_manager` logger and to `yarpmanager` GUI.
47+
* The time info can be displayed as the current time (obtained from `std::chrono::system_clock::now()`) or as time elapsed since yarpmanager GUI launch
48+
4549
### Libraries
4650

4751
#### `libYARP_sig`
@@ -62,7 +66,7 @@ New Features
6266
IMap2D
6367
INavigation2D
6468
IOdometry2D
65-
69+
6670
#### `devices`
6771

6872
* Updated all devices which use the interfaces employing the new class `ReturnValue`:

src/guis/yarpmanager/src-manager/clusterWidget.cpp

+36-7
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ void ClusterWidget::onRunServer()
157157
{
158158
updateServerEntries();
159159

160+
yarp::manager::ErrorLogger* logger = yarp::manager::ErrorLogger::Instance();
160161
std::string cmdRunServer = getSSHCmd(cluster.user, cluster.nsNode, cluster.ssh_options);
161162
if (ui->checkRos->isChecked())
162163
{
@@ -169,7 +170,8 @@ void ClusterWidget::onRunServer()
169170
if (system(cmdRunServer.c_str()) != 0)
170171
{
171172
std::string err = "ClusterWidget: failed to run the server on " + cluster.nsNode;
172-
logError(QString(err.c_str()));
173+
logger->addError(err);
174+
reportErrors();
173175
}
174176
else
175177
{
@@ -201,10 +203,13 @@ void ClusterWidget::onStopServer()
201203

202204
cmdStopServer = cmdStopServer + " killall yarpserver &";
203205

206+
yarp::manager::ErrorLogger* logger = yarp::manager::ErrorLogger::Instance();
207+
204208
if (system(cmdStopServer.c_str()) != 0)
205209
{
206210
std::string err = "ClusterWidget: failed to stop the server on " + cluster.nsNode;
207-
logError(QString(err.c_str()));
211+
logger->addError(err);
212+
reportErrors();
208213
}
209214
else
210215
{
@@ -232,10 +237,12 @@ void ClusterWidget::onKillServer()
232237

233238
cmdKillServer = cmdKillServer + " killall -9 yarpserver &";
234239

240+
yarp::manager::ErrorLogger* logger = yarp::manager::ErrorLogger::Instance();
235241
if (system(cmdKillServer.c_str()) != 0)
236242
{
237243
std::string err = "ClusterWidget: failed to kill the server on " + cluster.nsNode;
238-
logError(QString(err.c_str()));
244+
logger->addError(err);
245+
reportErrors();
239246
}
240247
else
241248
{
@@ -284,10 +291,12 @@ void ClusterWidget::onRunSelected()
284291
{
285292
cmdRunYarprun.append("'");
286293
}
294+
yarp::manager::ErrorLogger* logger = yarp::manager::ErrorLogger::Instance();
287295
if (system(cmdRunYarprun.c_str()) != 0)
288296
{
289297
std::string err = "ClusterWidget: failed to run yarprun on " + node.name;
290-
logError(QString(err.c_str()));
298+
logger->addError(err);
299+
reportErrors();
291300
}
292301
else
293302
{
@@ -322,10 +331,12 @@ void ClusterWidget::onStopSelected()
322331

323332
cmdStopYarprun.append(" yarprun --exit --on ").append(portName).append(" &");
324333

334+
yarp::manager::ErrorLogger* logger = yarp::manager::ErrorLogger::Instance();
325335
if (system(cmdStopYarprun.c_str()) != 0)
326336
{
327337
std::string err = "ClusterWidget: failed to stop yarprun on " + node.name;
328-
logError(QString(err.c_str()));
338+
logger->addError(err);
339+
reportErrors();
329340
}
330341
else
331342
{
@@ -354,10 +365,12 @@ void ClusterWidget::onKillSelected()
354365

355366
cmdKillYarprun.append(" killall -9 yarprun &");
356367

368+
yarp::manager::ErrorLogger* logger = yarp::manager::ErrorLogger::Instance();
357369
if (system(cmdKillYarprun.c_str()) != 0)
358370
{
359371
std::string err = "ClusterWidget: failed to kill yarprun on " + node.name;
360-
logError(QString(err.c_str()));
372+
logger->addError(err);
373+
reportErrors();
361374
}
362375
else
363376
{
@@ -399,10 +412,12 @@ void ClusterWidget::onExecute()
399412

400413
cmdExecute.append(" ").append(command);
401414

415+
yarp::manager::ErrorLogger* logger = yarp::manager::ErrorLogger::Instance();
402416
if (system(cmdExecute.c_str()) != 0)
403417
{
404418
std::string err = "ClusterWidget: failed to run "+ command + " on " + node.name;
405-
logError(QString(err.c_str()));
419+
logger->addError(err);
420+
reportErrors();
406421
}
407422
else
408423
{
@@ -594,6 +609,20 @@ void ClusterWidget::updateServerEntries()
594609
cluster.nsNode = ui->nsNodeComboBox->currentText().simplified().trimmed().toStdString();
595610
}
596611

612+
void ClusterWidget::reportErrors()
613+
{
614+
yarp::manager::ErrorLogger* logger = yarp::manager::ErrorLogger::Instance();
615+
if (logger->errorCount() || logger->warningCount())
616+
{
617+
const char* err;
618+
while((err=logger->getLastError()))
619+
{
620+
QString msg = QString("ClusterWidget: %1").arg(err);
621+
emit logError(msg);
622+
}
623+
}
624+
}
625+
597626
ClusterWidget::~ClusterWidget()
598627
{
599628
if (clusLoader)

src/guis/yarpmanager/src-manager/clusterWidget.h

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ private slots:
4747
bool checkNameserver();
4848
bool checkNode(const std::string& name);
4949
void updateServerEntries();
50+
void reportErrors();
5051

5152

5253
Ui::ClusterWidget *ui;

src/guis/yarpmanager/src-manager/main.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ Options:\n\
3333
--auto_connect \n\
3434
--auto_dependency \n\
3535
--add_current_dir add the current dir to the search path\n\
36+
--elapsed_time if present the time stamp for log messages will be relative to the GUI start time\n\
3637
"
3738

3839
#define DEF_CONFIG_FILE "ymanager.ini"
@@ -206,6 +207,12 @@ int main(int argc, char *argv[])
206207
config.put("auto_dependency", "no");
207208
}
208209

210+
if(!config.check("elapsed_time"))
211+
{
212+
yarp::manager::ClockStart& clock = yarp::manager::ClockStart::getInstance();
213+
clock.setStartTime("00:00:00");
214+
}
215+
209216
#if defined(_WIN32)
210217
//setup signal handler for windows
211218
// signal(SIGINT, onSignal);

src/guis/yarpmanager/src-manager/mainwindow.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,8 @@ void MainWindow::onLogWarning(QString msg)
890890
*/
891891
void MainWindow::onLogMessage(QString msg)
892892
{
893+
ClockStart& clock = ClockStart::getInstance();
894+
msg = QString("[time: %1] ").arg(getElapsedTimeString(clock.getStartTime()).c_str()) + msg;
893895
QString text = QString ("[MSG] %1").arg(msg);
894896
ui->logWidget->addItem(text);
895897
ui->logWidget->setCurrentRow(ui->logWidget->count() - 1);

src/libYARP_manager/src/yarp/manager/utility.cpp

+76-4
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,20 @@ ErrorLogger* ErrorLogger::Instance()
103103

104104
void ErrorLogger::addWarning(const char* szWarning) {
105105
if (szWarning) {
106-
warnings.emplace_back(szWarning);
106+
ClockStart& clock = ClockStart::getInstance();
107+
std::string elapsedTime = getElapsedTimeString(clock.getStartTime());
108+
std::string timeinfo = "[time: " + elapsedTime + "] ";
109+
std::string szWarningWithTime = timeinfo + szWarning;
110+
warnings.emplace_back(szWarningWithTime);
107111
}
108112
}
109113

110114
void ErrorLogger::addWarning(const std::string &str) {
111-
warnings.push_back(str);
115+
ClockStart& clock = ClockStart::getInstance();
116+
std::string elapsedTime = getElapsedTimeString(clock.getStartTime());
117+
std::string timeinfo = "[time: " + elapsedTime + "] ";
118+
std::string strWithTime = timeinfo + str;
119+
warnings.push_back(strWithTime);
112120
}
113121

114122
void ErrorLogger::addWarning(OSTRINGSTREAM &stream) {
@@ -117,12 +125,20 @@ void ErrorLogger::addWarning(OSTRINGSTREAM &stream) {
117125

118126
void ErrorLogger::addError(const char* szError) {
119127
if (szError) {
120-
errors.emplace_back(szError);
128+
ClockStart& clock = ClockStart::getInstance();
129+
std::string elapsedTime = getElapsedTimeString(clock.getStartTime());
130+
std::string timeinfo = "[time: " + elapsedTime + "] ";
131+
std::string szErrorWithTime = timeinfo + szError;
132+
errors.emplace_back(szErrorWithTime);
121133
}
122134
}
123135

124136
void ErrorLogger::addError(const std::string &str) {
125-
errors.push_back(str);
137+
ClockStart& clock = ClockStart::getInstance();
138+
std::string elapsedTime = getElapsedTimeString(clock.getStartTime());
139+
std::string timeinfo = "[time: " + elapsedTime + "] ";
140+
std::string strWithTime = timeinfo + str;
141+
errors.push_back(strWithTime);
126142
}
127143

128144
void ErrorLogger::addError(OSTRINGSTREAM &stream) {
@@ -328,6 +344,62 @@ bool yarp::manager::compareString(const char* szFirst, const char* szSecond)
328344
return false;
329345
}
330346

347+
std::string yarp::manager::getCurrentTimeString() {
348+
auto now = std::chrono::system_clock::now();
349+
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
350+
351+
std::tm localTime;
352+
#ifdef _WIN32
353+
localtime_s(&localTime, &currentTime); // Windows
354+
#else
355+
localtime_r(&currentTime, &localTime); // POSIX
356+
#endif
357+
std::ostringstream oss;
358+
oss << std::put_time(&localTime, "%H:%M:%S");
359+
return oss.str();
360+
}
361+
362+
std::string yarp::manager::getElapsedTimeString(const std::string& startTimeStr) {
363+
std::tm startTime{};
364+
std::istringstream iss(startTimeStr);
365+
iss >> std::get_time(&startTime, "%H:%M:%S");
366+
if (iss.fail()) {
367+
throw std::invalid_argument("Invalid time format. Expected %H:%M:%S");
368+
}
369+
370+
auto now = std::chrono::system_clock::now();
371+
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
372+
373+
std::tm localTime;
374+
#ifdef _WIN32
375+
localtime_s(&localTime, &currentTime); // Windows
376+
#else
377+
localtime_r(&currentTime, &localTime); // POSIX
378+
#endif
379+
380+
localTime.tm_hour = startTime.tm_hour;
381+
localTime.tm_min = startTime.tm_min;
382+
localTime.tm_sec = startTime.tm_sec;
383+
384+
std::time_t startTimestamp = std::mktime(&localTime);
385+
386+
auto elapsedSeconds = std::difftime(currentTime, startTimestamp);
387+
if (elapsedSeconds < 0) {
388+
elapsedSeconds += 24 * 60 * 60; // Handle cases where the start time is on the previous day
389+
}
390+
391+
int hours = static_cast<int>(elapsedSeconds) / 3600;
392+
int minutes = (static_cast<int>(elapsedSeconds) % 3600) / 60;
393+
int seconds = static_cast<int>(elapsedSeconds) % 60;
394+
395+
std::ostringstream oss;
396+
oss << std::setfill('0') << std::setw(2) << hours << ":"
397+
<< std::setfill('0') << std::setw(2) << minutes << ":"
398+
<< std::setfill('0') << std::setw(2) << seconds;
399+
400+
return oss.str();
401+
}
402+
331403
void yarp::manager::trimString(std::string& str)
332404
{
333405
std::string::size_type pos = str.find_last_not_of(' ');

src/libYARP_manager/src/yarp/manager/utility.h

+59
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <cstring>
1414
#include <iostream>
1515
#include <sstream>
16+
#include <chrono>
17+
#include <iomanip>
1618

1719
#include <yarp/manager/ymm-types.h>
1820

@@ -78,8 +80,65 @@ class ErrorLogger
7880
std::vector<std::string> warnings;
7981
};
8082

83+
/**
84+
* Singleton class For storing execution start time
85+
*/
86+
class ClockStart {
87+
public:
88+
static ClockStart& getInstance() {
89+
static ClockStart instance;
90+
return instance;
91+
}
92+
93+
ClockStart(const ClockStart&) = delete;
94+
ClockStart& operator=(const ClockStart&) = delete;
95+
96+
/**
97+
* @brief Get the starting time as a string in HH:MM:SS format
98+
* @return the starting time as a string
99+
*/
100+
std::string getStartTime() const {
101+
std::ostringstream oss;
102+
oss << std::put_time(&startTimeStruct, "%H:%M:%S");
103+
return oss.str();
104+
}
105+
106+
/**
107+
* @brief Set the starting time from a string in HH:MM:SS format
108+
* @param startTimeStr the starting time as a string
109+
*/
110+
void setStartTime(std::string startTimeStr) {
111+
std::istringstream iss(startTimeStr);
112+
std::tm tm = {};
113+
if (iss >> std::get_time(&tm, "%H:%M:%S")) {
114+
startTimeStruct = tm;
115+
}
116+
}
117+
118+
private:
119+
std::chrono::system_clock::time_point startTime;
120+
std::tm startTimeStruct;
121+
122+
/**
123+
* @brief Private constructor to initialize the start time
124+
* @details The start time is initialized to the current time
125+
*/
126+
ClockStart() {
127+
startTime = std::chrono::system_clock::now();
128+
std::time_t startTimeT = std::chrono::system_clock::to_time_t(startTime);
129+
130+
#ifdef _WIN32
131+
localtime_s(&startTimeStruct, &startTimeT);
132+
#else
133+
localtime_r(&startTimeT, &startTimeStruct);
134+
#endif
135+
}
136+
};
137+
81138

82139
bool compareString(const char* szFirst, const char* szSecond);
140+
std::string getCurrentTimeString();
141+
std::string getElapsedTimeString(const std::string& startTimeStr);
83142
void trimString(std::string& str);
84143
OS strToOS(const char* szOS);
85144

src/yarpmanager-console/ymanager.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ Options:\n\
9797
--silent Do not print the status messages (should be used with --application)\n\
9898
--exit Immediately exit after executing the commands (should be used with --application)\n\
9999
--from <conf> Configuration file name\n\
100+
--elapsed_time if present the time stamp for log messages will be relative to the GUI start time\n\
100101
--version Show current version\n\
101102
--help Show help\n"
102103

@@ -152,6 +153,13 @@ YConsoleManager::YConsoleManager(int argc, char* argv[]) : Manager()
152153
return;
153154
}
154155

156+
// I the option elapsed_time is not set, set the start time to 00:00:00 (For error and warning logging)
157+
if(!config.check("elapsed_time"))
158+
{
159+
yarp::manager::ClockStart& clock = yarp::manager::ClockStart::getInstance();
160+
clock.setStartTime("00:00:00");
161+
}
162+
155163
/**
156164
* preparing default options
157165
*/

0 commit comments

Comments
 (0)