From 798a9dd9b1e521144b7243782c95b845ba526b8d Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Mon, 9 Nov 2020 21:18:13 +0100 Subject: [PATCH] WIP: support command-line redirection of stdout/stderr --- src/OpenFOAM/Make/files | 1 + src/OpenFOAM/global/argList/argList.C | 55 +++++- src/OpenFOAM/global/argList/argList.H | 6 + src/OpenFOAM/global/argList/argListHelp.C | 10 + src/OpenFOAM/global/argList/argListRedirect.C | 175 ++++++++++++++++++ src/OpenFOAM/global/argList/argListRedirect.H | 86 +++++++++ 6 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 src/OpenFOAM/global/argList/argListRedirect.C create mode 100644 src/OpenFOAM/global/argList/argListRedirect.H diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files index d08e7dde6e0..9e905b05666 100644 --- a/src/OpenFOAM/Make/files +++ b/src/OpenFOAM/Make/files @@ -5,6 +5,7 @@ global/globals.C /* global/JobInfo/JobInfo.C in globals.C */ global/argList/argList.C global/argList/argListHelp.C +global/argList/argListRedirect.C global/clock/clock.C global/clockValue/clockValue.C global/cpuTime/cpuTimeCxx.C diff --git a/src/OpenFOAM/global/argList/argList.C b/src/OpenFOAM/global/argList/argList.C index 6ded4cec85d..c0c91d85865 100644 --- a/src/OpenFOAM/global/argList/argList.C +++ b/src/OpenFOAM/global/argList/argList.C @@ -27,6 +27,7 @@ License \*---------------------------------------------------------------------------*/ #include "argList.H" +#include "argListRedirect.H" #include "OSspecific.H" #include "Switch.H" #include "clock.H" @@ -47,6 +48,7 @@ License #include "stringListOps.H" #include "fileOperation.H" #include "fileOperationInitialise.H" +#include "fstreamPointer.H" #include <cctype> @@ -911,7 +913,9 @@ Foam::argList::argList runControl_(), args_(argc), options_(argc), - libs_() + libs_(), + stdout_(nullptr), + stderr_(nullptr) { // Pre-scan for some options needed for initial setup: // -fileHandler (takes an argument) @@ -1018,6 +1022,53 @@ Foam::argList::argList // ------------------------------------------------------------------------ + // Capture stdout/stderr redirection names. Filters argv + Detail::redirectOutputs redirects(argc, argv); + + // Perform output redirection + if (redirects.active()) + { + word suffix; + + if (redirects.ranks_ && parRunControl_.parRun()) + { + suffix = Foam::name(Pstream::myProcNo()); + } + + if (!redirects.stdout_.empty()) + { + fileName file(fileName::validate(redirects.stdout_)); + file.ext(suffix); + + stdout_.reset(ofstreamPointer(file).release()); + } + + if (!redirects.stderr_.empty()) + { + fileName file(fileName::validate(redirects.stderr_)); + file.ext(suffix); + + stderr_.reset(ofstreamPointer(file).release()); + } + + if (stdout_) + { + Sout.attach(*stdout_); + Pout.attach(*stdout_); + } + + if (stderr_) + { + Serr.attach(*stderr_); + Perr.attach(*stderr_); + } + else if (redirects.join_) + { + Serr.attach(Sout.stdStream()); + Perr.attach(Sout.stdStream()); + } + } + // Convert argv -> args_ and capture ( ... ) lists regroupArgv(argc, argv); @@ -1172,6 +1223,8 @@ Foam::argList::argList args_(args.args_), options_(options), libs_(), + stdout_(nullptr), + stderr_(nullptr), executable_(args.executable_), rootPath_(args.rootPath_), globalCase_(args.globalCase_), diff --git a/src/OpenFOAM/global/argList/argList.H b/src/OpenFOAM/global/argList/argList.H index 0b0efa5844b..6ab381ee617 100644 --- a/src/OpenFOAM/global/argList/argList.H +++ b/src/OpenFOAM/global/argList/argList.H @@ -146,6 +146,12 @@ class argList //- Additional libraries mutable dlLibraryTable libs_; + //- File redirection for stdout (Sout, Pout) + std::unique_ptr<std::ostream> stdout_; + + //- File redirection for stderr (Serr, Perr) + std::unique_ptr<std::ostream> stderr_; + word executable_; fileName rootPath_; fileName globalCase_; diff --git a/src/OpenFOAM/global/argList/argListHelp.C b/src/OpenFOAM/global/argList/argListHelp.C index 042e4297343..9bd82f22939 100644 --- a/src/OpenFOAM/global/argList/argListHelp.C +++ b/src/OpenFOAM/global/argList/argListHelp.C @@ -425,6 +425,16 @@ void Foam::argList::printUsage(bool full) const } + // Redirections + if (full) + { + printOption("stdout <file>", "Redirect stdout to file"); + printOption("stderr <file>", "Redirect stderr to file"); + printOption("join-stderr", "Join stderr to stdout"); + printOption("append-rank", "Append stdout/stderr files with MPI-rank"); + } + + // Place documentation/help options at the end printOption("doc", "Display documentation in browser"); diff --git a/src/OpenFOAM/global/argList/argListRedirect.C b/src/OpenFOAM/global/argList/argListRedirect.C new file mode 100644 index 00000000000..157e04b7332 --- /dev/null +++ b/src/OpenFOAM/global/argList/argListRedirect.C @@ -0,0 +1,175 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "argListRedirect.H" +#include "IOstreams.H" +#include "boolList.H" + +// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // + +namespace +{ + +inline bool opt_join(const char* optName) +{ + return strcmp(optName, "join-stderr") == 0; +} + +inline bool opt_rank(const char* optName) +{ + return strcmp(optName, "append-rank") == 0; +} + +inline bool opt_stderr(const char* optName) +{ + return strcmp(optName, "stderr") == 0; +} + +inline bool opt_stdout(const char* optName) +{ + return strcmp(optName, "stdout") == 0; +} + +} // End anonymous namespace + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::Detail::redirectOutputs::redirectOutputs(int& argc, char**& argv) +: + stdout_(), + stderr_(), + join_(false), + ranks_(false) +{ + List<bool> skip(label(argc), false); + bool filter = false; + + for (int argi = 1; argi < argc-1; ++argi) + { + if (argv[argi][0] == '-') + { + const char *optName = &argv[argi][1]; + + if (opt_join(optName)) + { + join_ = true; + filter = true; + skip[argi] = true; + } + else if (opt_rank(optName)) + { + ranks_ = true; + filter = true; + skip[argi] = true; + } + else if (opt_stdout(optName)) + { + stdout_ = argv[argi+1]; + filter = true; + skip[argi] = true; + skip[argi+1] = true; + ++argi; + } + else if (opt_stderr(optName)) + { + stderr_ = argv[argi+1]; + filter = true; + skip[argi] = true; + skip[argi+1] = true; + ++argi; + } + } + } + + + // Test final arg separately + { + const int argi = argc-1; + + if (argi > 0 && argv[argi][0] == '-') + { + const char *optName = &argv[argi][1]; + + if (opt_join(optName)) + { + join_ = true; + filter = true; + skip[argi] = true; + } + else if (opt_rank(optName)) + { + ranks_ = true; + filter = true; + skip[argi] = true; + } + } + } + + + if (filter) + { + int nArgs = 1; + + for (int argi = 1; argi < argc; ++argi) + { + if (!skip[argi]) + { + argv[nArgs] = argv[argi]; + ++nArgs; + } + } + argc = nArgs; + } + + + // Resolve potential conflicts + + if (!stderr_.empty()) + { + if (stdout_.empty()) + { + join_ = false; + } + else if (stdout_ == stderr_) + { + join_ = true; + stderr_.clear(); + } + } +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::Detail::redirectOutputs::active() const +{ + return join_ || !stdout_.empty() || !stderr_.empty(); +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/global/argList/argListRedirect.H b/src/OpenFOAM/global/argList/argListRedirect.H new file mode 100644 index 00000000000..5c78cd4f532 --- /dev/null +++ b/src/OpenFOAM/global/argList/argListRedirect.H @@ -0,0 +1,86 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::Detail::redirectOutputs + +Description + Helper class for redirecting outputs from within argList. + Handles the following options: + + \verbatim + -stdout <file> + -stderr <file> + -join-stderr + -append-rank + \endverbatim + +Note + Not intended for general use + +SourceFiles + argListRedirect.C + +\*---------------------------------------------------------------------------*/ + +#ifndef argListRedirect_H +#define argListRedirect_H + +#include "string.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace Detail +{ + +/*---------------------------------------------------------------------------*\ + Class redirectOutputs Declaration +\*---------------------------------------------------------------------------*/ + +struct redirectOutputs +{ + string stdout_; + string stderr_; + bool join_; + bool ranks_; + + redirectOutputs(int& argc, char**& argv); + + bool active() const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Detail +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // -- GitLab