FIMS  v0.9.2
Loading...
Searching...
No Matches
def.hpp
Go to the documentation of this file.
1
8#ifndef DEF_HPP
9#define DEF_HPP
10#include <fstream>
11#include <map>
12#include <memory>
13#include <vector>
14#include <string>
15#include <unordered_map>
16
17#include <cstdlib>
18#include <chrono>
19#include <sstream>
20#include <iostream>
21#include <filesystem>
22#include <stdlib.h>
23#include <fstream>
24#include <signal.h>
25#include <csignal>
26#include <cstring>
27
28#include <stdexcept>
29
30#if defined(linux) || defined(__linux) || defined(__linux__)
31#define FIMS_LINUX
32#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
33 defined(__DragonFly__)
34#define FIMS_BSD
35#elif defined(sun) || defined(__sun)
36#define FIMS_SOLARIS
37#elif defined(__sgi)
38#define FIMS_IRIX
39#elif defined(__hpux)
40#define FIMS_HPUX
41#elif defined(__CYGWIN__)
42#define FIMS_CYGWIN
43#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
44#define FIMS_WIN32
45#elif defined(_WIN64) || defined(__WIN64__) || defined(WIN64)
46#define FIMS_WIN64
47#elif defined(__BEOS__)
48#define FIMS_BEOS
49#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
50#define FIMS_MACOS
51#elif defined(__IBMCPP__) || defined(_AIX)
52#define FIMS_AIX
53#elif defined(__amigaos__)
54#define FIMS_AMIGAOS
55#elif defined(__QNXNTO__)
56#define FIMS_QNXNTO
57#endif
58
59#if defined(FIMS_WIN32) || defined(FIMS_WIN64)
60#define FIMS_WINDOWS
61#endif
62
63#ifdef FIMS_WINDOWS
64#include <Windows.h>
65#undef TRUE
66#undef FALSE
67#include <Lmcons.h> // for UNLEN
68#elif defined(FIMS_LINUX) || defined(FIMS_MACOS) || defined(FIMS_BSD)
69#include <unistd.h>
70#include <pwd.h>
71#endif
72
73#if !defined(__PRETTY_FUNCTION__) && !defined(__GNUC__)
74#ifdef FIMS_WINDOWS
75#define __PRETTY_FUNCTION__ __FUNCTION__
76#endif
77#endif
78
79// The following rows initialize default log files for outputting model progress
80// comments used to assist in diagnosing model issues and tracking progress.
81
82#ifdef TMB_MODEL
83// simplify access to singletons
84#define TMB_FIMS_REAL_TYPE double
85#define TMBAD_FIMS_TYPE TMBad::ad_aug
86#endif
87
88/* Dictionary block for shared documentation.
89 [params_for_message]
90 @param str Log message text.
91 @param line Source line number where the message originated.
92 @param file Source file where the message originated.
93 @param func Function or method name where the message originated.
94 [params_for_message]
95*/
96
97/* Dictionary block for shared documentation.
98 [param_MESSAGE]
99 @param MESSAGE Human-readable log message describing what happened and why.
100 [param_MESSAGE]
101*/
102
103namespace fims {
104
112struct LogEntry {
119 std::string timestamp;
126 std::string message;
134 std::string level;
140 size_t rank;
145 std::string user;
151 std::string wd;
157 std::string file;
165 std::string routine;
170 int line;
171
176 std::string to_string() {
177 std::stringstream ss;
178 ss << "\"timestamp\": " << "\"" << this->timestamp << "\"" << ",\n";
179 ss << "\"level\": " << "\"" << this->level << "\",\n";
180 ss << "\"message\": " << "\"" << this->message << "\",\n";
181 ss << "\"id\": " << "\"" << this->rank << "\",\n";
182 ss << "\"user\": " << "\"" << this->user << "\",\n";
183 ss << "\"wd\": " << "\"" << this->wd << "\",\n";
184 ss << "\"file\": " << "\"" << this->file << "\",\n";
185 ss << "\"routine\": " << "\"" << this->routine << "\",\n";
186 ss << "\"line\": " << "\"" << this->line << "\"\n";
187 return ss.str();
188 }
189};
190
203class FIMSLog {
204 std::vector<std::string> entries;
205 std::vector<LogEntry> log_entries;
206 size_t entry_number = 0;
207 std::string path = "fims.log";
208 size_t warning_count = 0;
209 size_t error_count = 0;
210
216 std::string get_user() {
217#ifdef FIMS_WINDOWS
218 char username[UNLEN + 1];
219 DWORD username_len = UNLEN + 1;
220 if (GetUserNameA(username, &username_len)) {
221 return std::string(username);
222 } else {
223 return "[unknown user]";
224 }
225
226#elif defined(FIMS_LINUX) || defined(FIMS_MACOS) || defined(FIMS_BSD)
227 const char* user_env = getenv("USER");
228 if (user_env) return std::string(user_env);
229
230 uid_t uid = getuid();
231 struct passwd* pw = getpwuid(uid);
232 if (pw && pw->pw_name) {
233 return std::string(pw->pw_name);
234 } else {
235 return "[unknown user]";
236 }
237
238#else
239 return "[unsupported platform]";
240#endif
241 }
242
243 public:
249 bool write_on_exit = true;
256 bool throw_on_error = false;
263 static std::shared_ptr<FIMSLog> fims_log;
264
269
275 if (this->write_on_exit) {
276 std::ofstream log(this->path);
277 log << this->get_log();
278 log.close();
279 }
280 }
281
291 std::filesystem::path getAbsolutePathWithoutDotDot(
292 const std::filesystem::path& relativePath) {
293 std::filesystem::path absolutePath =
294 std::filesystem::absolute(relativePath);
295
296 std::filesystem::path result;
297 for (const auto& part : absolutePath) {
298 if (part == "..") {
299 if (!result.empty()) {
300 result = result.parent_path();
301 }
302 } else {
303 result /= part;
304 }
305 }
306
307 return result.generic_string();
308 }
309
325 void set_path(std::string path) { this->path = path; }
326
332 std::string get_path() { return this->path; }
333
341 void info_message(std::string str, int line, const char* file,
342 const char* func) {
343 std::filesystem::path relativePath = file;
344 std::filesystem::path absolutePath =
345 getAbsolutePathWithoutDotDot(relativePath);
346 std::filesystem::path cwd = std::filesystem::current_path();
347 std::stringstream ss;
348 auto now = std::chrono::system_clock::now();
349 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
350 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
351
352 LogEntry l;
353 l.timestamp = ctime_no_newline;
354 l.message = str;
355 l.level = "info";
356 l.rank = this->log_entries.size();
357 l.user = this->get_user();
358 l.wd = cwd.generic_string();
359 l.file = absolutePath.string();
360 l.line = line;
361 l.routine = func;
362 this->log_entries.push_back(l);
363 }
364
372 void error_message(std::string str, int line, const char* file,
373 const char* func) {
374 this->error_count++;
375 std::filesystem::path relativePath = file;
376 std::filesystem::path absolutePath =
377 getAbsolutePathWithoutDotDot(relativePath);
378 std::filesystem::path cwd = std::filesystem::current_path();
379
380 std::stringstream ss;
381 auto now = std::chrono::system_clock::now();
382 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
383 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
384
385 LogEntry l;
386 l.timestamp = ctime_no_newline;
387 l.message = str;
388 l.level = "error";
389 l.rank = this->log_entries.size();
390 l.user = this->get_user();
391 l.wd = cwd.generic_string();
392 l.file = absolutePath.string();
393 l.line = line;
394 l.routine = func;
395 this->log_entries.push_back(l);
396
397 if (this->throw_on_error) {
398 std::stringstream ss;
399 ss << "\n\n" << l.to_string() << "\n\n";
400 throw std::runtime_error(ss.str().c_str());
401 }
402 }
403
411 void warning_message(std::string str, int line, const char* file,
412 const char* func) {
413 this->warning_count++;
414 std::filesystem::path relativePath = file;
415 std::filesystem::path absolutePath =
416 getAbsolutePathWithoutDotDot(relativePath);
417 std::filesystem::path cwd = std::filesystem::current_path();
418
419 std::stringstream ss;
420 auto now = std::chrono::system_clock::now();
421 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
422 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
423
424 LogEntry l;
425 l.timestamp = ctime_no_newline;
426 l.message = str;
427 l.level = "warning";
428 l.rank = this->log_entries.size();
429 l.user = this->get_user();
430 l.wd = cwd.generic_string();
431 l.file = absolutePath.string();
432 l.line = line;
433 l.routine = func;
434 this->log_entries.push_back(l);
435 }
436
451 std::string get_log() {
452 std::stringstream ss;
453 if (log_entries.size() == 0) {
454 ss << "[\n]";
455 } else {
456 ss << "[\n";
457 for (size_t i = 0; i < log_entries.size() - 1; i++) {
458 ss << "{\n" << this->log_entries[i].to_string() << "},\n";
459 }
460 ss << "{\n"
461 << this->log_entries[log_entries.size() - 1].to_string() << "}\n]";
462 }
463 return ss.str();
464 }
465
480 std::string get_errors() {
481 std::stringstream ss;
482 std::vector<LogEntry> errors;
483 for (size_t i = 0; i < log_entries.size(); i++) {
484 if (log_entries[i].level == "error") {
485 errors.push_back(this->log_entries[i]);
486 }
487 }
488
489 if (errors.size() == 0) {
490 ss << "[\n]";
491 } else {
492 ss << "[\n";
493 for (size_t i = 0; i < errors.size() - 1; i++) {
494 ss << "{\n" << errors[i].to_string() << "},\n";
495 }
496
497 ss << "{\n" << errors[errors.size() - 1].to_string() << "}\n]";
498 }
499 return ss.str();
500 }
501
517 std::string get_warnings() {
518 std::stringstream ss;
519 std::vector<LogEntry> warnings;
520 for (size_t i = 0; i < log_entries.size(); i++) {
521 if (log_entries[i].level == "warning") {
522 warnings.push_back(this->log_entries[i]);
523 }
524 }
525
526 if (warnings.size() == 0) {
527 ss << "[\n]";
528 } else {
529 ss << "[\n";
530 for (size_t i = 0; i < warnings.size() - 1; i++) {
531 ss << "{\n" << warnings[i].to_string() << "},\n";
532 }
533
534 ss << "{\n" << warnings[warnings.size() - 1].to_string() << "}\n]";
535 }
536 return ss.str();
537 }
538
553 std::string get_info() {
554 std::stringstream ss;
555 std::vector<LogEntry> info;
556 for (size_t i = 0; i < log_entries.size(); i++) {
557 if (log_entries[i].level == "info") {
558 info.push_back(this->log_entries[i]);
559 }
560 }
561
562 if (info.size() == 0) {
563 ss << "[\n]";
564 } else {
565 ss << "[\n";
566 for (size_t i = 0; i < info.size() - 1; i++) {
567 ss << "{\n" << info[i].to_string() << "},\n";
568 }
569
570 ss << "{\n" << info[info.size() - 1].to_string() << "}\n]";
571 }
572 return ss.str();
573 }
574
584 size_t get_error_count() const { return error_count; }
585
595 size_t get_warning_count() const { return warning_count; }
596
604 void clear() {
605 this->entries.clear();
606 this->log_entries.clear();
607 this->error_count = 0;
608 this->warning_count = 0;
609 this->entry_number = 0;
610 }
611};
612
613std::shared_ptr<FIMSLog> FIMSLog::fims_log = std::make_shared<FIMSLog>();
614
615} // namespace fims
616
627#define FIMS_INFO_LOG(MESSAGE) \
628 fims::FIMSLog::fims_log->info_message(MESSAGE, __LINE__, __FILE__, \
629 __PRETTY_FUNCTION__);
630
639#define FIMS_WARNING_LOG(MESSAGE) \
640 fims::FIMSLog::fims_log->warning_message(MESSAGE, __LINE__, __FILE__, \
641 __PRETTY_FUNCTION__);
642
655#define FIMS_ERROR_LOG(MESSAGE) \
656 fims::FIMSLog::fims_log->error_message(MESSAGE, __LINE__, __FILE__, \
657 __PRETTY_FUNCTION__);
658
664#define FIMS_STR(s) #s
665
666namespace fims {
667
680void WriteAtExit(int sig) {
681 std::string signal_error = "NA";
682 switch (sig) {
683 case SIGSEGV:
684 signal_error = "Invalid memory access (segmentation fault)";
685 break;
686 case SIGINT:
687 signal_error = "External interrupt, possibly initiated by the user.";
688 break;
689 case SIGABRT:
690 signal_error =
691 "Abnormal termination condition, possible call to std::abort.";
692 break;
693 case SIGFPE:
694 signal_error = "Erroneous arithmetic operation.";
695 break;
696 case SIGILL:
697 signal_error = "Invalid program image or invalid instruction";
698 break;
699 case SIGTERM:
700 signal_error = "Termination request, sent to the program.";
701 break;
702 default:
703 signal_error = "Unknown signal thrown";
704 }
705
706 FIMSLog::fims_log->error_message(signal_error, -999, "?", "?");
707
708 if (FIMSLog::fims_log->write_on_exit) {
709 std::ofstream log(FIMSLog::fims_log->get_path());
710 log << FIMSLog::fims_log->get_log();
711 log.close();
712 }
713 std::signal(sig, SIG_DFL);
714 raise(sig);
715}
716
725template <typename T>
726std::string to_string(T v) {
727 std::stringstream ss;
728 ss << v;
729 return ss.str();
730}
731
732} // namespace fims
733
734#endif /* TRAITS_HPP */
Singleton logger for FIMS.
Definition def.hpp:203
void error_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:372
void clear()
Clear in-memory logging state.
Definition def.hpp:604
bool write_on_exit
A boolean specifying if the log file is written when the session is terminated. The default is TRUE.
Definition def.hpp:249
bool throw_on_error
A boolean specifying if the program is stopped upon the first error, where the default is FALSE....
Definition def.hpp:256
std::string get_log()
Return all stored log entries as a JSON array string.
Definition def.hpp:451
void warning_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:411
size_t get_warning_count() const
Return the number of warning-log entries currently stored.
Definition def.hpp:595
std::string get_warnings()
Return only warning-level log entries as a JSON array string.
Definition def.hpp:517
std::string get_path()
Get the current output path for on-disk logs.
Definition def.hpp:332
static std::shared_ptr< FIMSLog > fims_log
A singleton instance of the log, i.e., where there is only one log. The object is created when the ....
Definition def.hpp:263
FIMSLog()
Definition def.hpp:268
std::string get_errors()
Return only error-level log entries as a JSON array string.
Definition def.hpp:480
void set_path(std::string path)
Set the destination file path for writing logs to disk.
Definition def.hpp:325
~FIMSLog()
Definition def.hpp:274
std::filesystem::path getAbsolutePathWithoutDotDot(const std::filesystem::path &relativePath)
Get the absolute path without dot dot notation.
Definition def.hpp:291
size_t get_error_count() const
Return the number of error-log entries currently stored.
Definition def.hpp:584
void info_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:341
std::string get_info()
Return only info-level log entries as a JSON array string.
Definition def.hpp:553
void WriteAtExit(int sig)
Signal handler that records a terminal error and flushes log entries.
Definition def.hpp:680
std::string to_string(T v)
Definition def.hpp:726
A data structure with defined fields for a single log record.
Definition def.hpp:112
std::string wd
The working directory for the environment that created the log.
Definition def.hpp:151
size_t rank
The message identifier corresponding to creation order.
Definition def.hpp:140
std::string file
The full file path of the file that triggered the log entry.
Definition def.hpp:157
std::string routine
The function or method that initiated the log entry.
Definition def.hpp:165
std::string level
The logging level associated with the entry.
Definition def.hpp:134
std::string message
The description of the log entry.
Definition def.hpp:126
int line
The line in file where the log entry was initiated.
Definition def.hpp:170
std::string timestamp
The date and time that the log entry was created.
Definition def.hpp:119
std::string to_string()
Serialize this entry to a JSON object string.
Definition def.hpp:176
std::string user
The user name registered on the machine where the log was created.
Definition def.hpp:145