Skip to content

Commit 02cd06d

Browse files
committed
Handle output log directory creation and log file dumping
1 parent b45b6c6 commit 02cd06d

4 files changed

Lines changed: 68 additions & 9 deletions

File tree

src/global.cpp

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@
88
#include <iostream>
99
#include <string>
1010
#include <sstream>
11+
12+
#if __has_include(<filesystem>)
13+
#include <filesystem> // NOLINT [build/c++17]
14+
namespace fs = std::filesystem;
15+
#elif __has_include(<experimental/filesystem>)
16+
#include <experimental/filesystem>
17+
namespace fs = std::experimental::filesystem;
18+
#else
19+
#error "Missing the <filesystem> header."
20+
#endif
21+
1122
#include "idefix.hpp"
1223
#include "global.hpp"
1324
#include "profiler.hpp"
@@ -105,12 +116,34 @@ void IdefixOutStream::init(int rank) {
105116

106117

107118
// disable the log file
108-
void IdefixOutStream::enableLogFile() {
119+
void IdefixOutStream::enableLogFile(const std::string &logDirectory) {
109120
std::stringstream sslogFileName;
110121
sslogFileName << "idefix." << idfx::prank << ".log";
111122

112-
std::string logFileName(sslogFileName.str());
123+
std::string logFileName;
124+
if(!logDirectory.empty()) {
125+
fs::path outputDirectory(logDirectory);
126+
std::error_code errorCode;
127+
// Attempt to create the directory. We deliberately ignore the boolean return
128+
// value of create_directories: when several MPI processes call this function
129+
// concurrently, only one of them actually creates the directory while the
130+
// others get a "false" return (nothing created) even though no error
131+
// occurred. Relying on that return value would make the losing ranks abort
132+
// spuriously. Instead, we verify success by checking that the path exists as
133+
// a directory afterwards, which is robust to this race condition.
134+
fs::create_directories(outputDirectory, errorCode);
135+
if(!fs::is_directory(outputDirectory)) {
136+
IDEFIX_ERROR("Unable to create log directory " + logDirectory);
137+
}
138+
logFileName = (outputDirectory / sslogFileName.str()).string();
139+
} else {
140+
logFileName = sslogFileName.str();
141+
}
142+
113143
this->my_fstream.open(logFileName.c_str());
144+
if(!this->my_fstream.is_open()) {
145+
IDEFIX_ERROR("Unable to open log file " + logFileName);
146+
}
114147

115148
this->logFileEnabled = true;
116149
}

src/global.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ void DumpArray(std::string filename, ArrayType array) {
6666
class idfx::IdefixOutStream {
6767
public:
6868
void init(int);
69-
void enableLogFile();
69+
void enableLogFile(const std::string &logDirectory = "");
7070
// for regular output of variables and stuff
7171
template<typename T> IdefixOutStream& operator<<(const T& something) {
7272
if(toscreen) std::cout << something;

src/input.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@
1616
#include <vector>
1717
#include <memory>
1818

19+
#if __has_include(<filesystem>)
20+
#include <filesystem> // NOLINT [build/c++17]
21+
namespace fs = std::filesystem;
22+
#elif __has_include(<experimental/filesystem>)
23+
#include <experimental/filesystem>
24+
namespace fs = std::experimental::filesystem;
25+
#else
26+
#error "Missing the <filesystem> header."
27+
#endif
28+
1929
#include "idefix.hpp"
2030
#include "input.hpp"
2131
#include "version.hpp"
@@ -57,6 +67,15 @@ Input::Input(int argc, char* argv[] ) {
5767
// Parse command line (may replace the input file)
5868
ParseCommandLine(argc,argv);
5969

70+
// Determine executable directory. This is the fallback log destination when
71+
// [Output]:log_dir is not defined in the input file.
72+
fs::path executablePath(argv[0]);
73+
std::error_code errorCode;
74+
executablePath = fs::absolute(executablePath, errorCode);
75+
if(!errorCode && executablePath.has_parent_path()) {
76+
this->executableDirectory = executablePath.parent_path().string();
77+
}
78+
6079
file.open(this->inputFileName);
6180

6281
if(!file) {
@@ -108,12 +127,20 @@ Input::Input(int argc, char* argv[] ) {
108127
}
109128
}
110129
file.close();
130+
131+
if(this->enableLogs) {
132+
if(CheckEntry("Output","log_dir") > 0) {
133+
idfx::cout.enableLogFile(Get<std::string>("Output","log_dir",0));
134+
} else {
135+
idfx::cout.enableLogFile(this->executableDirectory);
136+
}
137+
}
111138
}
112139

113140
// This routine parse command line options
114141
void Input::ParseCommandLine(int argc, char **argv) {
115142
std::stringstream msg;
116-
bool enableLogs = true;
143+
this->enableLogs = true;
117144
for(int i = 1 ; i < argc ; i++) {
118145
// MPI decomposition argument
119146
if(std::string(argv[i]) == "-dec") {
@@ -171,9 +198,9 @@ void Input::ParseCommandLine(int argc, char **argv) {
171198
this->forceInitRequested = true;
172199
} else if(std::string(argv[i]) == "-nowrite") {
173200
this->forceNoWrite = true;
174-
enableLogs = false;
201+
this->enableLogs = false;
175202
} else if(std::string(argv[i]) == "-nolog") {
176-
enableLogs = false;
203+
this->enableLogs = false;
177204
} else if(std::string(argv[i]) == "-profile") {
178205
idfx::prof.EnablePerformanceProfiling();
179206
} else if(std::string(argv[i]) == "-Werror") {
@@ -190,9 +217,6 @@ void Input::ParseCommandLine(int argc, char **argv) {
190217
IDEFIX_ERROR(msg);
191218
}
192219
}
193-
if(enableLogs) {
194-
idfx::cout.enableLogFile();
195-
}
196220
}
197221

198222

src/input.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ class Input {
7373
Kokkos::Timer timer;
7474

7575
double lastStopFileCheck;
76+
bool enableLogs{true};
77+
std::string executableDirectory{"."};
7678
};
7779

7880
// Template functions

0 commit comments

Comments
 (0)