FIMS  v0.8.0
Loading...
Searching...
No Matches
def.hpp
Go to the documentation of this file.
1
9#ifndef DEF_HPP
10#define DEF_HPP
11#include <fstream>
12#include <map>
13#include <memory>
14#include <vector>
15#include <string>
16#include <unordered_map>
17
18#include <cstdlib>
19#include <chrono>
20#include <sstream>
21#include <iostream>
22#include <filesystem>
23#include <stdlib.h>
24#include <fstream>
25#include <signal.h>
26#include <csignal>
27#include <cstring>
28
29#include <stdexcept>
30
31#if defined(linux) || defined(__linux) || defined(__linux__)
32#define FIMS_LINUX
33#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
34 defined(__DragonFly__)
35#define FIMS_BSD
36#elif defined(sun) || defined(__sun)
37#define FIMS_SOLARIS
38#elif defined(__sgi)
39#define FIMS_IRIX
40#elif defined(__hpux)
41#define FIMS_HPUX
42#elif defined(__CYGWIN__)
43#define FIMS_CYGWIN
44#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
45#define FIMS_WIN32
46#elif defined(_WIN64) || defined(__WIN64__) || defined(WIN64)
47#define FIMS_WIN64
48#elif defined(__BEOS__)
49#define FIMS_BEOS
50#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
51#define FIMS_MACOS
52#elif defined(__IBMCPP__) || defined(_AIX)
53#define FIMS_AIX
54#elif defined(__amigaos__)
55#define FIMS_AMIGAOS
56#elif defined(__QNXNTO__)
57#define FIMS_QNXNTO
58#endif
59
60#if defined(FIMS_WIN32) || defined(FIMS_WIN64)
61#define FIMS_WINDOWS
62#endif
63
64#ifdef FIMS_WINDOWS
65#include <Windows.h>
66#include <Lmcons.h> // for UNLEN
67#elif defined(FIMS_LINUX) || defined(FIMS_MACOS) || defined(FIMS_BSD)
68#include <unistd.h>
69#include <pwd.h>
70#endif
71
72#if !defined(__PRETTY_FUNCTION__) && !defined(__GNUC__)
73#ifdef FIMS_WINDOWS
74#define __PRETTY_FUNCTION__ __FUNCTION__
75#endif
76#endif
77
78// The following rows initialize default log files for outputting model progress
79// comments used to assist in diagnosing model issues and tracking progress.
80// These files will only be created if a logs folder is added to the root model
81// directory.
82
83#ifdef TMB_MODEL
84// simplify access to singletons
85#define TMB_FIMS_REAL_TYPE double
86#ifdef TMBAD_FRAMEWORK
87#define TMBAD_FIMS_TYPE TMBad::ad_aug
88#else
89#define TMB_FIMS_FIRST_ORDER AD<TMB_FIMS_REAL_TYPE>
90#define TMB_FIMS_SECOND_ORDER AD<TMB_FIMS_FIRST_ORDER>
91#define TMB_FIMS_THIRD_ORDER AD<TMB_FIMS_SECOND_ORDER>
92#endif
93#endif
94
95namespace fims {
96
100struct LogEntry {
104 std::string timestamp;
109 std::string message;
116 std::string level;
121 size_t rank;
124 std::string user;
129 std::string wd;
132 std::string file;
138 std::string routine;
141 int line;
142
146 std::string to_string() {
147 std::stringstream ss;
148 ss << "\"timestamp\": " << "\"" << this->timestamp << "\"" << ",\n";
149 ss << "\"level\": " << "\"" << this->level << "\",\n";
150 ss << "\"message\": " << "\"" << this->message << "\",\n";
151 ss << "\"id\": " << "\"" << this->rank << "\",\n";
152 ss << "\"user\": " << "\"" << this->user << "\",\n";
153 ss << "\"wd\": " << "\"" << this->wd << "\",\n";
154 ss << "\"file\": " << "\"" << this->file << "\",\n";
155 ss << "\"routine\": " << "\"" << this->routine << "\",\n";
156 ss << "\"line\": " << "\"" << this->line << "\"\n";
157 return ss.str();
158 }
159};
160
164class FIMSLog {
165 std::vector<std::string> entries;
166 std::vector<LogEntry> log_entries;
167 size_t entry_number = 0;
168 std::string path = "fims.log";
169 size_t warning_count = 0;
170 size_t error_count = 0;
171
177 std::string get_user() {
178#ifdef FIMS_WINDOWS
179 char username[UNLEN + 1];
180 DWORD username_len = UNLEN + 1;
181 if (GetUserNameA(username, &username_len)) {
182 return std::string(username);
183 } else {
184 return "[unknown user]";
185 }
186
187#elif defined(FIMS_LINUX) || defined(FIMS_MACOS) || defined(FIMS_BSD)
188 const char* user_env = getenv("USER");
189 if (user_env) return std::string(user_env);
190
191 uid_t uid = getuid();
192 struct passwd* pw = getpwuid(uid);
193 if (pw && pw->pw_name) {
194 return std::string(pw->pw_name);
195 } else {
196 return "[unknown user]";
197 }
198
199#else
200 return "[unsupported platform]";
201#endif
202 }
203
204 public:
210 bool write_on_exit = true;
217 bool throw_on_error = false;
224 static std::shared_ptr<FIMSLog> fims_log;
225
230
236 if (this->write_on_exit) {
237 std::ofstream log(this->path);
238 log << this->get_log();
239 log.close();
240 }
241 }
242
252 std::filesystem::path getAbsolutePathWithoutDotDot(
253 const std::filesystem::path& relativePath) {
254 std::filesystem::path absolutePath =
255 std::filesystem::absolute(relativePath);
256
257 std::filesystem::path result;
258 for (const auto& part : absolutePath) {
259 if (part == "..") {
260 if (!result.empty()) {
261 result = result.parent_path();
262 }
263 } else {
264 result /= part;
265 }
266 }
267
268 return result.generic_string();
269 }
270
276 void set_path(std::string path) { this->path = path; }
277
283 std::string get_path() { return this->path; }
284
293 void info_message(std::string str, int line, const char* file,
294 const char* func) {
295 std::filesystem::path relativePath = file;
296 std::filesystem::path absolutePath =
297 getAbsolutePathWithoutDotDot(relativePath);
298 std::filesystem::path cwd = std::filesystem::current_path();
299 std::stringstream ss;
300 auto now = std::chrono::system_clock::now();
301 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
302 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
303
304 LogEntry l;
305 l.timestamp = ctime_no_newline;
306 l.message = str;
307 l.level = "info";
308 l.rank = this->log_entries.size();
309 l.user = this->get_user();
310 l.wd = cwd.generic_string();
311 l.file = absolutePath.string();
312 l.line = line;
313 l.routine = func;
314 this->log_entries.push_back(l);
315 }
316
325 void debug_message(std::string str, int line, const char* file,
326 const char* func) {
327 std::filesystem::path relativePath = file;
328 std::filesystem::path absolutePath =
329 getAbsolutePathWithoutDotDot(relativePath);
330 std::filesystem::path cwd = std::filesystem::current_path();
331 std::stringstream ss;
332 auto now = std::chrono::system_clock::now();
333 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
334 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
335
336 LogEntry l;
337 l.timestamp = ctime_no_newline;
338 l.message = str;
339 l.level = "debug";
340 l.rank = this->log_entries.size();
341 l.user = this->get_user();
342 l.wd = cwd.generic_string();
343 l.file = absolutePath.string();
344 l.line = line;
345 l.routine = func;
346 this->log_entries.push_back(l);
347 }
348
357 void error_message(std::string str, int line, const char* file,
358 const char* func) {
359 this->error_count++;
360 std::filesystem::path relativePath = file;
361 std::filesystem::path absolutePath =
362 getAbsolutePathWithoutDotDot(relativePath);
363 std::filesystem::path cwd = std::filesystem::current_path();
364
365 std::stringstream ss;
366 auto now = std::chrono::system_clock::now();
367 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
368 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
369
370 LogEntry l;
371 l.timestamp = ctime_no_newline;
372 l.message = str;
373 l.level = "error";
374 l.rank = this->log_entries.size();
375 l.user = this->get_user();
376 l.wd = cwd.generic_string();
377 l.file = absolutePath.string();
378 l.line = line;
379 l.routine = func;
380 this->log_entries.push_back(l);
381
382 if (this->throw_on_error) {
383 std::stringstream ss;
384 ss << "\n\n" << l.to_string() << "\n\n";
385 throw std::runtime_error(ss.str().c_str());
386 }
387 }
388
397 void warning_message(std::string str, int line, const char* file,
398 const char* func) {
399 this->warning_count++;
400 std::filesystem::path relativePath = file;
401 std::filesystem::path absolutePath =
402 getAbsolutePathWithoutDotDot(relativePath);
403 std::filesystem::path cwd = std::filesystem::current_path();
404
405 std::stringstream ss;
406 auto now = std::chrono::system_clock::now();
407 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
408 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
409
410 LogEntry l;
411 l.timestamp = ctime_no_newline;
412 l.message = str;
413 l.level = "warning";
414 l.rank = this->log_entries.size();
415 l.user = this->get_user();
416 l.wd = cwd.generic_string();
417 l.file = absolutePath.string();
418 l.line = line;
419 l.routine = func;
420 this->log_entries.push_back(l);
421 }
422
428 std::string get_log() {
429 std::stringstream ss;
430 if (log_entries.size() == 0) {
431 ss << "[\n]";
432 } else {
433 ss << "[\n";
434 for (size_t i = 0; i < log_entries.size() - 1; i++) {
435 ss << "{\n" << this->log_entries[i].to_string() << "},\n";
436 }
437 ss << "{\n"
438 << this->log_entries[log_entries.size() - 1].to_string() << "}\n]";
439 }
440 return ss.str();
441 }
442
448 std::string get_errors() {
449 std::stringstream ss;
450 std::vector<LogEntry> errors;
451 for (size_t i = 0; i < log_entries.size(); i++) {
452 if (log_entries[i].level == "error") {
453 errors.push_back(this->log_entries[i]);
454 }
455 }
456
457 if (errors.size() == 0) {
458 ss << "[\n]";
459 } else {
460 ss << "[\n";
461 for (size_t i = 0; i < errors.size() - 1; i++) {
462 ss << "{\n" << errors[i].to_string() << "},\n";
463 }
464
465 ss << "{\n" << errors[errors.size() - 1].to_string() << "}\n]";
466 }
467 return ss.str();
468 }
469
475 std::string get_warnings() {
476 std::stringstream ss;
477 std::vector<LogEntry> warnings;
478 for (size_t i = 0; i < log_entries.size(); i++) {
479 if (log_entries[i].level == "warning") {
480 warnings.push_back(this->log_entries[i]);
481 }
482 }
483
484 if (warnings.size() == 0) {
485 ss << "[\n]";
486 } else {
487 ss << "[\n";
488 for (size_t i = 0; i < warnings.size() - 1; i++) {
489 ss << "{\n" << warnings[i].to_string() << "},\n";
490 }
491
492 ss << "{\n" << warnings[warnings.size() - 1].to_string() << "}\n]";
493 }
494 return ss.str();
495 }
496
502 std::string get_info() {
503 std::stringstream ss;
504 std::vector<LogEntry> info;
505 for (size_t i = 0; i < log_entries.size(); i++) {
506 if (log_entries[i].level == "info") {
507 info.push_back(this->log_entries[i]);
508 }
509 }
510
511 if (info.size() == 0) {
512 ss << "[\n]";
513 } else {
514 ss << "[\n";
515 for (size_t i = 0; i < info.size() - 1; i++) {
516 ss << "{\n" << info[i].to_string() << "},\n";
517 }
518
519 ss << "{\n" << info[info.size() - 1].to_string() << "}\n]";
520 }
521 return ss.str();
522 }
523
530 std::string get_module(const std::string& module) {
531 std::stringstream ss;
532 std::vector<LogEntry> info;
533 for (size_t i = 0; i < log_entries.size(); i++) {
534 if (log_entries[i].file.find(module) != std::string::npos) {
535 info.push_back(this->log_entries[i]);
536 }
537 }
538
539 if (info.size() == 0) {
540 ss << "[\n]";
541 } else {
542 ss << "[\n";
543 for (size_t i = 0; i < info.size() - 1; i++) {
544 ss << "{\n" << info[i].to_string() << "},\n";
545 }
546
547 ss << "{\n" << info[info.size() - 1].to_string() << "}\n]";
548 }
549 return ss.str();
550 }
551
555 size_t get_error_count() const { return error_count; }
556
560 size_t get_warning_count() const { return warning_count; }
561
566 void clear() {
567 this->entries.clear();
568 this->log_entries.clear();
569 this->warning_count = 0;
570 this->entry_number = 0;
571 }
572};
573
574std::shared_ptr<FIMSLog> FIMSLog::fims_log = std::make_shared<FIMSLog>();
575
576} // namespace fims
577
578#ifdef FIMS_DEBUG
579
580#define FIMS_DEBUG_LOG(MESSAGE) \
581 FIMSLog::fims_log->debug_message(MESSAGE, __LINE__, __FILE__, \
582 __PRETTY_FUNCTION__);
583
584#else
585
586#define FIMS_DEBUG_LOG(MESSAGE)
588#endif
589
590#define FIMS_INFO_LOG(MESSAGE) \
591 fims::FIMSLog::fims_log->info_message( \
592 MESSAGE, __LINE__, __FILE__, \
593 __PRETTY_FUNCTION__);
595#define FIMS_WARNING_LOG(MESSAGE) \
596 fims::FIMSLog::fims_log->warning_message( \
597 MESSAGE, __LINE__, __FILE__, \
598 __PRETTY_FUNCTION__);
600#define FIMS_ERROR_LOG(MESSAGE) \
601 fims::FIMSLog::fims_log->error_message( \
602 MESSAGE, __LINE__, __FILE__, \
603 __PRETTY_FUNCTION__);
605#define FIMS_STR(s) #s
607namespace fims {
608
615void WriteAtExit(int sig) {
616 std::string signal_error = "NA";
617 switch (sig) {
618 case SIGSEGV:
619 signal_error = "Invalid memory access (segmentation fault)";
620 break;
621 case SIGINT:
622 signal_error = "External interrupt, possibly initiated by the user.";
623 break;
624 case SIGABRT:
625 signal_error =
626 "Abnormal termination condition, possible call to std::abort.";
627 break;
628 case SIGFPE:
629 signal_error = "Erroneous arithmetic operation.";
630 break;
631 case SIGILL:
632 signal_error = "Invalid program image or invalid instruction";
633 break;
634 case SIGTERM:
635 signal_error = "Termination request, sent to the program.";
636 break;
637 default:
638 signal_error = "Unknown signal thrown";
639 }
640
641 FIMSLog::fims_log->error_message(signal_error, -999, "?", "?");
642
643 if (FIMSLog::fims_log->write_on_exit) {
644 std::ofstream log(FIMSLog::fims_log->get_path());
645 log << FIMSLog::fims_log->get_log();
646 log.close();
647 }
648 std::signal(sig, SIG_DFL);
649 raise(sig);
650}
651
658template <typename T>
659std::string to_string(T v) {
660 std::stringstream ss;
661 ss << v;
662 return ss.str();
663}
664
665} // namespace fims
666
667#endif /* TRAITS_HPP */
Definition def.hpp:164
void debug_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:325
void error_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:357
void clear()
Clears all pointers/references of a FIMS model.
Definition def.hpp:566
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:210
bool throw_on_error
A boolean specifying if the program is stopped upon the first error, where the default is FALSE....
Definition def.hpp:217
std::string get_log()
Definition def.hpp:428
void warning_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:397
size_t get_warning_count() const
Get the counts of the number of warnings.
Definition def.hpp:560
std::string get_module(const std::string &module)
Definition def.hpp:530
std::string get_warnings()
Definition def.hpp:475
std::string get_path()
Definition def.hpp:283
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:224
FIMSLog()
Definition def.hpp:229
std::string get_errors()
Definition def.hpp:448
void set_path(std::string path)
Definition def.hpp:276
~FIMSLog()
Definition def.hpp:235
std::filesystem::path getAbsolutePathWithoutDotDot(const std::filesystem::path &relativePath)
Get the Absolute Path Without Dot Dot object.
Definition def.hpp:252
size_t get_error_count() const
Get the counts of the number of errors.
Definition def.hpp:555
void info_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:293
std::string get_info()
Definition def.hpp:502
std::string to_string(T v)
Definition def.hpp:668
Definition def.hpp:100
std::string wd
Definition def.hpp:129
size_t rank
Definition def.hpp:121
std::string file
Definition def.hpp:132
std::string routine
Definition def.hpp:138
std::string level
Definition def.hpp:116
std::string message
Definition def.hpp:109
int line
Definition def.hpp:141
std::string timestamp
Definition def.hpp:104
std::string to_string()
Definition def.hpp:146
std::string user
Definition def.hpp:124