FIMS  v0.8.1
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#define TMBAD_FIMS_TYPE TMBad::ad_aug
87#endif
88
89namespace fims {
90
94struct LogEntry {
98 std::string timestamp;
103 std::string message;
107 std::string level;
112 size_t rank;
115 std::string user;
120 std::string wd;
123 std::string file;
129 std::string routine;
132 int line;
133
137 std::string to_string() {
138 std::stringstream ss;
139 ss << "\"timestamp\": " << "\"" << this->timestamp << "\"" << ",\n";
140 ss << "\"level\": " << "\"" << this->level << "\",\n";
141 ss << "\"message\": " << "\"" << this->message << "\",\n";
142 ss << "\"id\": " << "\"" << this->rank << "\",\n";
143 ss << "\"user\": " << "\"" << this->user << "\",\n";
144 ss << "\"wd\": " << "\"" << this->wd << "\",\n";
145 ss << "\"file\": " << "\"" << this->file << "\",\n";
146 ss << "\"routine\": " << "\"" << this->routine << "\",\n";
147 ss << "\"line\": " << "\"" << this->line << "\"\n";
148 return ss.str();
149 }
150};
151
155class FIMSLog {
156 std::vector<std::string> entries;
157 std::vector<LogEntry> log_entries;
158 size_t entry_number = 0;
159 std::string path = "fims.log";
160 size_t warning_count = 0;
161 size_t error_count = 0;
162
168 std::string get_user() {
169#ifdef FIMS_WINDOWS
170 char username[UNLEN + 1];
171 DWORD username_len = UNLEN + 1;
172 if (GetUserNameA(username, &username_len)) {
173 return std::string(username);
174 } else {
175 return "[unknown user]";
176 }
177
178#elif defined(FIMS_LINUX) || defined(FIMS_MACOS) || defined(FIMS_BSD)
179 const char* user_env = getenv("USER");
180 if (user_env) return std::string(user_env);
181
182 uid_t uid = getuid();
183 struct passwd* pw = getpwuid(uid);
184 if (pw && pw->pw_name) {
185 return std::string(pw->pw_name);
186 } else {
187 return "[unknown user]";
188 }
189
190#else
191 return "[unsupported platform]";
192#endif
193 }
194
195 public:
201 bool write_on_exit = true;
208 bool throw_on_error = false;
215 static std::shared_ptr<FIMSLog> fims_log;
216
221
227 if (this->write_on_exit) {
228 std::ofstream log(this->path);
229 log << this->get_log();
230 log.close();
231 }
232 }
233
243 std::filesystem::path getAbsolutePathWithoutDotDot(
244 const std::filesystem::path& relativePath) {
245 std::filesystem::path absolutePath =
246 std::filesystem::absolute(relativePath);
247
248 std::filesystem::path result;
249 for (const auto& part : absolutePath) {
250 if (part == "..") {
251 if (!result.empty()) {
252 result = result.parent_path();
253 }
254 } else {
255 result /= part;
256 }
257 }
258
259 return result.generic_string();
260 }
261
267 void set_path(std::string path) { this->path = path; }
268
274 std::string get_path() { return this->path; }
275
284 void info_message(std::string str, int line, const char* file,
285 const char* func) {
286 std::filesystem::path relativePath = file;
287 std::filesystem::path absolutePath =
288 getAbsolutePathWithoutDotDot(relativePath);
289 std::filesystem::path cwd = std::filesystem::current_path();
290 std::stringstream ss;
291 auto now = std::chrono::system_clock::now();
292 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
293 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
294
295 LogEntry l;
296 l.timestamp = ctime_no_newline;
297 l.message = str;
298 l.level = "info";
299 l.rank = this->log_entries.size();
300 l.user = this->get_user();
301 l.wd = cwd.generic_string();
302 l.file = absolutePath.string();
303 l.line = line;
304 l.routine = func;
305 this->log_entries.push_back(l);
306 }
307
316 void error_message(std::string str, int line, const char* file,
317 const char* func) {
318 this->error_count++;
319 std::filesystem::path relativePath = file;
320 std::filesystem::path absolutePath =
321 getAbsolutePathWithoutDotDot(relativePath);
322 std::filesystem::path cwd = std::filesystem::current_path();
323
324 std::stringstream ss;
325 auto now = std::chrono::system_clock::now();
326 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
327 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
328
329 LogEntry l;
330 l.timestamp = ctime_no_newline;
331 l.message = str;
332 l.level = "error";
333 l.rank = this->log_entries.size();
334 l.user = this->get_user();
335 l.wd = cwd.generic_string();
336 l.file = absolutePath.string();
337 l.line = line;
338 l.routine = func;
339 this->log_entries.push_back(l);
340
341 if (this->throw_on_error) {
342 std::stringstream ss;
343 ss << "\n\n" << l.to_string() << "\n\n";
344 throw std::runtime_error(ss.str().c_str());
345 }
346 }
347
356 void warning_message(std::string str, int line, const char* file,
357 const char* func) {
358 this->warning_count++;
359 std::filesystem::path relativePath = file;
360 std::filesystem::path absolutePath =
361 getAbsolutePathWithoutDotDot(relativePath);
362 std::filesystem::path cwd = std::filesystem::current_path();
363
364 std::stringstream ss;
365 auto now = std::chrono::system_clock::now();
366 std::time_t now_time = std::chrono::system_clock::to_time_t(now);
367 std::string ctime_no_newline = strtok(ctime(&now_time), "\n");
368
369 LogEntry l;
370 l.timestamp = ctime_no_newline;
371 l.message = str;
372 l.level = "warning";
373 l.rank = this->log_entries.size();
374 l.user = this->get_user();
375 l.wd = cwd.generic_string();
376 l.file = absolutePath.string();
377 l.line = line;
378 l.routine = func;
379 this->log_entries.push_back(l);
380 }
381
387 std::string get_log() {
388 std::stringstream ss;
389 if (log_entries.size() == 0) {
390 ss << "[\n]";
391 } else {
392 ss << "[\n";
393 for (size_t i = 0; i < log_entries.size() - 1; i++) {
394 ss << "{\n" << this->log_entries[i].to_string() << "},\n";
395 }
396 ss << "{\n"
397 << this->log_entries[log_entries.size() - 1].to_string() << "}\n]";
398 }
399 return ss.str();
400 }
401
407 std::string get_errors() {
408 std::stringstream ss;
409 std::vector<LogEntry> errors;
410 for (size_t i = 0; i < log_entries.size(); i++) {
411 if (log_entries[i].level == "error") {
412 errors.push_back(this->log_entries[i]);
413 }
414 }
415
416 if (errors.size() == 0) {
417 ss << "[\n]";
418 } else {
419 ss << "[\n";
420 for (size_t i = 0; i < errors.size() - 1; i++) {
421 ss << "{\n" << errors[i].to_string() << "},\n";
422 }
423
424 ss << "{\n" << errors[errors.size() - 1].to_string() << "}\n]";
425 }
426 return ss.str();
427 }
428
434 std::string get_warnings() {
435 std::stringstream ss;
436 std::vector<LogEntry> warnings;
437 for (size_t i = 0; i < log_entries.size(); i++) {
438 if (log_entries[i].level == "warning") {
439 warnings.push_back(this->log_entries[i]);
440 }
441 }
442
443 if (warnings.size() == 0) {
444 ss << "[\n]";
445 } else {
446 ss << "[\n";
447 for (size_t i = 0; i < warnings.size() - 1; i++) {
448 ss << "{\n" << warnings[i].to_string() << "},\n";
449 }
450
451 ss << "{\n" << warnings[warnings.size() - 1].to_string() << "}\n]";
452 }
453 return ss.str();
454 }
455
461 std::string get_info() {
462 std::stringstream ss;
463 std::vector<LogEntry> info;
464 for (size_t i = 0; i < log_entries.size(); i++) {
465 if (log_entries[i].level == "info") {
466 info.push_back(this->log_entries[i]);
467 }
468 }
469
470 if (info.size() == 0) {
471 ss << "[\n]";
472 } else {
473 ss << "[\n";
474 for (size_t i = 0; i < info.size() - 1; i++) {
475 ss << "{\n" << info[i].to_string() << "},\n";
476 }
477
478 ss << "{\n" << info[info.size() - 1].to_string() << "}\n]";
479 }
480 return ss.str();
481 }
482
489 std::string get_module(const std::string& module) {
490 std::stringstream ss;
491 std::vector<LogEntry> info;
492 for (size_t i = 0; i < log_entries.size(); i++) {
493 if (log_entries[i].file.find(module) != std::string::npos) {
494 info.push_back(this->log_entries[i]);
495 }
496 }
497
498 if (info.size() == 0) {
499 ss << "[\n]";
500 } else {
501 ss << "[\n";
502 for (size_t i = 0; i < info.size() - 1; i++) {
503 ss << "{\n" << info[i].to_string() << "},\n";
504 }
505
506 ss << "{\n" << info[info.size() - 1].to_string() << "}\n]";
507 }
508 return ss.str();
509 }
510
514 size_t get_error_count() const { return error_count; }
515
519 size_t get_warning_count() const { return warning_count; }
520
525 void clear() {
526 this->entries.clear();
527 this->log_entries.clear();
528 this->warning_count = 0;
529 this->entry_number = 0;
530 }
531};
532
533std::shared_ptr<FIMSLog> FIMSLog::fims_log = std::make_shared<FIMSLog>();
534
535} // namespace fims
536
537#define FIMS_INFO_LOG(MESSAGE) \
538 fims::FIMSLog::fims_log->info_message( \
539 MESSAGE, __LINE__, __FILE__, \
540 __PRETTY_FUNCTION__);
542#define FIMS_WARNING_LOG(MESSAGE) \
543 fims::FIMSLog::fims_log->warning_message( \
544 MESSAGE, __LINE__, __FILE__, \
545 __PRETTY_FUNCTION__);
547#define FIMS_ERROR_LOG(MESSAGE) \
548 fims::FIMSLog::fims_log->error_message( \
549 MESSAGE, __LINE__, __FILE__, \
550 __PRETTY_FUNCTION__);
552#define FIMS_STR(s) #s
554namespace fims {
555
562void WriteAtExit(int sig) {
563 std::string signal_error = "NA";
564 switch (sig) {
565 case SIGSEGV:
566 signal_error = "Invalid memory access (segmentation fault)";
567 break;
568 case SIGINT:
569 signal_error = "External interrupt, possibly initiated by the user.";
570 break;
571 case SIGABRT:
572 signal_error =
573 "Abnormal termination condition, possible call to std::abort.";
574 break;
575 case SIGFPE:
576 signal_error = "Erroneous arithmetic operation.";
577 break;
578 case SIGILL:
579 signal_error = "Invalid program image or invalid instruction";
580 break;
581 case SIGTERM:
582 signal_error = "Termination request, sent to the program.";
583 break;
584 default:
585 signal_error = "Unknown signal thrown";
586 }
587
588 FIMSLog::fims_log->error_message(signal_error, -999, "?", "?");
589
590 if (FIMSLog::fims_log->write_on_exit) {
591 std::ofstream log(FIMSLog::fims_log->get_path());
592 log << FIMSLog::fims_log->get_log();
593 log.close();
594 }
595 std::signal(sig, SIG_DFL);
596 raise(sig);
597}
598
605template <typename T>
606std::string to_string(T v) {
607 std::stringstream ss;
608 ss << v;
609 return ss.str();
610}
611
612} // namespace fims
613
614#endif /* TRAITS_HPP */
Definition def.hpp:155
void error_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:316
void clear()
Clears all pointers/references of a FIMS model.
Definition def.hpp:525
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:201
bool throw_on_error
A boolean specifying if the program is stopped upon the first error, where the default is FALSE....
Definition def.hpp:208
std::string get_log()
Definition def.hpp:387
void warning_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:356
size_t get_warning_count() const
Get the counts of the number of warnings.
Definition def.hpp:519
std::string get_module(const std::string &module)
Definition def.hpp:489
std::string get_warnings()
Definition def.hpp:434
std::string get_path()
Definition def.hpp:274
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:215
FIMSLog()
Definition def.hpp:220
std::string get_errors()
Definition def.hpp:407
void set_path(std::string path)
Definition def.hpp:267
~FIMSLog()
Definition def.hpp:226
std::filesystem::path getAbsolutePathWithoutDotDot(const std::filesystem::path &relativePath)
Get the Absolute Path Without Dot Dot object.
Definition def.hpp:243
size_t get_error_count() const
Get the counts of the number of errors.
Definition def.hpp:514
void info_message(std::string str, int line, const char *file, const char *func)
Definition def.hpp:284
std::string get_info()
Definition def.hpp:461
std::string to_string(T v)
Definition def.hpp:615
Definition def.hpp:94
std::string wd
Definition def.hpp:120
size_t rank
Definition def.hpp:112
std::string file
Definition def.hpp:123
std::string routine
Definition def.hpp:129
std::string level
Definition def.hpp:107
std::string message
Definition def.hpp:103
int line
Definition def.hpp:132
std::string timestamp
Definition def.hpp:98
std::string to_string()
Definition def.hpp:137
std::string user
Definition def.hpp:115