FIMS  v0.9.3
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#ifndef NOMINMAX
65#define NOMINMAX
66#endif
67#ifndef WIN32_LEAN_AND_MEAN
68#define WIN32_LEAN_AND_MEAN
69#endif
70#include <Windows.h>
71#undef TRUE
72#undef FALSE
73#undef GetObject
74#include <Lmcons.h> // for UNLEN
75#elif defined(FIMS_LINUX) || defined(FIMS_MACOS) || defined(FIMS_BSD)
76#include <unistd.h>
77#include <pwd.h>
78#endif
79
80#if !defined(__PRETTY_FUNCTION__) && !defined(__GNUC__)
81#ifdef FIMS_WINDOWS
82#define __PRETTY_FUNCTION__ __FUNCTION__
83#endif
84#endif
85
86// The following rows initialize default log files for outputting model progress
87// comments used to assist in diagnosing model issues and tracking progress.
88
89#ifdef TMB_MODEL
90// simplify access to singletons
91#define TMB_FIMS_REAL_TYPE double
92#define TMBAD_FIMS_TYPE TMBad::ad_aug
93#endif
94
95/* Dictionary block for shared documentation.
96 [params_for_message]
97 @param str Log message text.
98 @param line Source line number where the message originated.
99 @param file Source file where the message originated.
100 @param func Function or method name where the message originated.
101 [params_for_message]
102*/
103
104/* Dictionary block for shared documentation.
105 [param_MESSAGE]
106 @param MESSAGE Human-readable log message describing what happened and why.
107 [param_MESSAGE]
108*/
109
110namespace fims {
111
119struct LogEntry {
126 std::string timestamp;
133 std::string message;
141 std::string level;
147 size_t rank;
152 std::string user;
158 std::string wd;
164 std::string file;
172 std::string routine;
177 int line;
178
183 std::string to_string() {
184 std::stringstream ss;
185 ss << "\"timestamp\": " << "\"" << this->timestamp << "\"" << ",\n";
186 ss << "\"level\": " << "\"" << this->level << "\",\n";
187 ss << "\"message\": " << "\"" << this->message << "\",\n";
188 ss << "\"id\": " << "\"" << this->rank << "\",\n";
189 ss << "\"user\": " << "\"" << this->user << "\",\n";
190 ss << "\"wd\": " << "\"" << this->wd << "\",\n";
191 ss << "\"file\": " << "\"" << this->file << "\",\n";
192 ss << "\"routine\": " << "\"" << this->routine << "\",\n";
193 ss << "\"line\": " << "\"" << this->line << "\"\n";
194 return ss.str();
195 }
196};
197
210class FIMSLog {
211 std::vector<std::string> entries;
212 std::vector<LogEntry> log_entries;
213 size_t entry_number = 0;
214 std::string path = "fims.log";
215 size_t warning_count = 0;
216 size_t error_count = 0;
217
223 std::string get_user() {
224#ifdef FIMS_WINDOWS
225 char username[UNLEN + 1];
226 DWORD username_len = UNLEN + 1;
227 if (GetUserNameA(username, &username_len)) {
228 return std::string(username);
229 } else {
230 return "[unknown user]";
231 }
232
233#elif defined(FIMS_LINUX) || defined(FIMS_MACOS) || defined(FIMS_BSD)
234 const char* user_env = getenv("USER");
235 if (user_env) return std::string(user_env);
236
237 uid_t uid = getuid();
238 struct passwd* pw = getpwuid(uid);
239 if (pw && pw->pw_name) {
240 return std::string(pw->pw_name);
241 } else {
242 return "[unknown user]";
243 }
244
245#else
246 return "[unsupported platform]";
247#endif
248 }
249
250 public:
256 bool write_on_exit = true;
263 bool throw_on_error = false;
270 static std::shared_ptr<FIMSLog> fims_log;
271
276
282 if (this->write_on_exit) {
283 std::ofstream log(this->path);
284 log << this->get_log();
285 log.close();
286 }
287 }
288
298 std::filesystem::path getAbsolutePathWithoutDotDot(
299 const std::filesystem::path& relativePath) {
300 std::filesystem::path absolutePath =
301 std::filesystem::absolute(relativePath);
302
303 std::filesystem::path result;
304 for (const auto& part : absolutePath) {
305 if (part == "..") {
306 if (!result.empty()) {
307 result = result.parent_path();
308 }
309 } else {
310 result /= part;
311 }
312 }
313
314 return result.generic_string();
315 }
316
332 void set_path(std::string path) { this->path = path; }
333
339 std::string get_path() { return this->path; }
340
348 void info_message(std::string str, int line, const char* file,
349 const char* func) {
350 std::filesystem::path relativePath = file;
351 std::filesystem::path absolutePath =
352 getAbsolutePathWithoutDotDot(relativePath);
353 std::filesystem::path cwd = std::filesystem::current_path();
354 std::stringstream ss;
355 auto now = std::chrono::system_clock::now();
356 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
357 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
358
359 LogEntry l;
360 l.timestamp = ctime_no_newline;
361 l.message = str;
362 l.level = "info";
363 l.rank = this->log_entries.size();
364 l.user = this->get_user();
365 l.wd = cwd.generic_string();
366 l.file = absolutePath.string();
367 l.line = line;
368 l.routine = func;
369 this->log_entries.push_back(l);
370 }
371
379 void error_message(std::string str, int line, const char* file,
380 const char* func) {
381 this->error_count++;
382 std::filesystem::path relativePath = file;
383 std::filesystem::path absolutePath =
384 getAbsolutePathWithoutDotDot(relativePath);
385 std::filesystem::path cwd = std::filesystem::current_path();
386
387 std::stringstream ss;
388 auto now = std::chrono::system_clock::now();
389 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
390 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
391
392 LogEntry l;
393 l.timestamp = ctime_no_newline;
394 l.message = str;
395 l.level = "error";
396 l.rank = this->log_entries.size();
397 l.user = this->get_user();
398 l.wd = cwd.generic_string();
399 l.file = absolutePath.string();
400 l.line = line;
401 l.routine = func;
402 this->log_entries.push_back(l);
403
404 if (this->throw_on_error) {
405 std::stringstream ss;
406 ss << "\n\n" << l.to_string() << "\n\n";
407 throw std::runtime_error(ss.str().c_str());
408 }
409 }
410
418 void warning_message(std::string str, int line, const char* file,
419 const char* func) {
420 this->warning_count++;
421 std::filesystem::path relativePath = file;
422 std::filesystem::path absolutePath =
423 getAbsolutePathWithoutDotDot(relativePath);
424 std::filesystem::path cwd = std::filesystem::current_path();
425
426 std::stringstream ss;
427 auto now = std::chrono::system_clock::now();
428 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
429 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
430
431 LogEntry l;
432 l.timestamp = ctime_no_newline;
433 l.message = str;
434 l.level = "warning";
435 l.rank = this->log_entries.size();
436 l.user = this->get_user();
437 l.wd = cwd.generic_string();
438 l.file = absolutePath.string();
439 l.line = line;
440 l.routine = func;
441 this->log_entries.push_back(l);
442 }
443
458 std::string get_log() {
459 std::stringstream ss;
460 if (log_entries.size() == 0) {
461 ss << "[\n]";
462 } else {
463 ss << "[\n";
464 for (size_t i = 0; i < log_entries.size() - 1; i++) {
465 ss << "{\n" << this->log_entries[i].to_string() << "},\n";
466 }
467 ss << "{\n"
468 << this->log_entries[log_entries.size() - 1].to_string() << "}\n]";
469 }
470 return ss.str();
471 }
472
487 std::string get_errors() {
488 std::stringstream ss;
489 std::vector<LogEntry> errors;
490 for (size_t i = 0; i < log_entries.size(); i++) {
491 if (log_entries[i].level == "error") {
492 errors.push_back(this->log_entries[i]);
493 }
494 }
495
496 if (errors.size() == 0) {
497 ss << "[\n]";
498 } else {
499 ss << "[\n";
500 for (size_t i = 0; i < errors.size() - 1; i++) {
501 ss << "{\n" << errors[i].to_string() << "},\n";
502 }
503
504 ss << "{\n" << errors[errors.size() - 1].to_string() << "}\n]";
505 }
506 return ss.str();
507 }
508
524 std::string get_warnings() {
525 std::stringstream ss;
526 std::vector<LogEntry> warnings;
527 for (size_t i = 0; i < log_entries.size(); i++) {
528 if (log_entries[i].level == "warning") {
529 warnings.push_back(this->log_entries[i]);
530 }
531 }
532
533 if (warnings.size() == 0) {
534 ss << "[\n]";
535 } else {
536 ss << "[\n";
537 for (size_t i = 0; i < warnings.size() - 1; i++) {
538 ss << "{\n" << warnings[i].to_string() << "},\n";
539 }
540
541 ss << "{\n" << warnings[warnings.size() - 1].to_string() << "}\n]";
542 }
543 return ss.str();
544 }
545
560 std::string get_info() {
561 std::stringstream ss;
562 std::vector<LogEntry> info;
563 for (size_t i = 0; i < log_entries.size(); i++) {
564 if (log_entries[i].level == "info") {
565 info.push_back(this->log_entries[i]);
566 }
567 }
568
569 if (info.size() == 0) {
570 ss << "[\n]";
571 } else {
572 ss << "[\n";
573 for (size_t i = 0; i < info.size() - 1; i++) {
574 ss << "{\n" << info[i].to_string() << "},\n";
575 }
576
577 ss << "{\n" << info[info.size() - 1].to_string() << "}\n]";
578 }
579 return ss.str();
580 }
581
591 size_t get_error_count() const { return error_count; }
592
602 size_t get_warning_count() const { return warning_count; }
603
611 void clear() {
612 this->entries.clear();
613 this->log_entries.clear();
614 this->error_count = 0;
615 this->warning_count = 0;
616 this->entry_number = 0;
617 }
618};
619
620#ifdef FIMS_HEADER_ONLY
621std::shared_ptr<FIMSLog> FIMSLog::fims_log = std::make_shared<FIMSLog>();
622#endif
623
624} // namespace fims
625
636#define FIMS_INFO_LOG(MESSAGE) \
637 fims::FIMSLog::fims_log->info_message(MESSAGE, __LINE__, __FILE__, \
638 __PRETTY_FUNCTION__);
639
648#define FIMS_WARNING_LOG(MESSAGE) \
649 fims::FIMSLog::fims_log->warning_message(MESSAGE, __LINE__, __FILE__, \
650 __PRETTY_FUNCTION__);
651
664#define FIMS_ERROR_LOG(MESSAGE) \
665 fims::FIMSLog::fims_log->error_message(MESSAGE, __LINE__, __FILE__, \
666 __PRETTY_FUNCTION__);
667
673#define FIMS_STR(s) #s
674
675namespace fims {
676
689inline void WriteAtExit(int sig) {
690 std::string signal_error = "NA";
691 switch (sig) {
692 case SIGSEGV:
693 signal_error = "Invalid memory access (segmentation fault)";
694 break;
695 case SIGINT:
696 signal_error = "External interrupt, possibly initiated by the user.";
697 break;
698 case SIGABRT:
699 signal_error =
700 "Abnormal termination condition, possible call to std::abort.";
701 break;
702 case SIGFPE:
703 signal_error = "Erroneous arithmetic operation.";
704 break;
705 case SIGILL:
706 signal_error = "Invalid program image or invalid instruction";
707 break;
708 case SIGTERM:
709 signal_error = "Termination request, sent to the program.";
710 break;
711 default:
712 signal_error = "Unknown signal thrown";
713 }
714
715 FIMSLog::fims_log->error_message(signal_error, -999, "?", "?");
716
717 if (FIMSLog::fims_log->write_on_exit) {
718 std::ofstream log(FIMSLog::fims_log->get_path());
719 log << FIMSLog::fims_log->get_log();
720 log.close();
721 }
722 std::signal(sig, SIG_DFL);
723 raise(sig);
724}
725
734template <typename T>
735std::string to_string(T v) {
736 std::stringstream ss;
737 ss << v;
738 return ss.str();
739}
740
741} // namespace fims
742
743#endif /* TRAITS_HPP */
Singleton logger for FIMS.
Definition def.hpp:210
void error_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:379
void clear()
Clear in-memory logging state.
Definition def.hpp:611
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:256
bool throw_on_error
A boolean specifying if the program is stopped upon the first error, where the default is FALSE....
Definition def.hpp:263
std::string get_log()
Return all stored log entries as a JSON array string.
Definition def.hpp:458
void warning_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:418
size_t get_warning_count() const
Return the number of warning-log entries currently stored.
Definition def.hpp:602
std::string get_warnings()
Return only warning-level log entries as a JSON array string.
Definition def.hpp:524
std::string get_path()
Get the current output path for on-disk logs.
Definition def.hpp:339
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:270
FIMSLog()
Definition def.hpp:275
std::string get_errors()
Return only error-level log entries as a JSON array string.
Definition def.hpp:487
void set_path(std::string path)
Set the destination file path for writing logs to disk.
Definition def.hpp:332
~FIMSLog()
Definition def.hpp:281
std::filesystem::path getAbsolutePathWithoutDotDot(const std::filesystem::path &relativePath)
Get the absolute path without dot dot notation.
Definition def.hpp:298
size_t get_error_count() const
Return the number of error-log entries currently stored.
Definition def.hpp:591
void info_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:348
std::string get_info()
Return only info-level log entries as a JSON array string.
Definition def.hpp:560
void WriteAtExit(int sig)
Signal handler that records a terminal error and flushes log entries.
Definition def.hpp:689
std::string to_string(T v)
Definition def.hpp:735
A data structure with defined fields for a single log record.
Definition def.hpp:119
std::string wd
The working directory for the environment that created the log.
Definition def.hpp:158
size_t rank
The message identifier corresponding to creation order.
Definition def.hpp:147
std::string file
The full file path of the file that triggered the log entry.
Definition def.hpp:164
std::string routine
The function or method that initiated the log entry.
Definition def.hpp:172
std::string level
The logging level associated with the entry.
Definition def.hpp:141
std::string message
The description of the log entry.
Definition def.hpp:133
int line
The line in file where the log entry was initiated.
Definition def.hpp:177
std::string timestamp
The date and time that the log entry was created.
Definition def.hpp:126
std::string to_string()
Serialize this entry to a JSON object string.
Definition def.hpp:183
std::string user
The user name registered on the machine where the log was created.
Definition def.hpp:152