WIP: support command-line redirection of stdout/stderr

This commit is contained in:
Mark Olesen 2020-11-09 21:18:13 +01:00
parent fe1e056196
commit 798a9dd9b1
6 changed files with 332 additions and 1 deletions

View File

@ -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

View File

@ -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_),

View File

@ -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_;

View File

@ -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");

View File

@ -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();
}
// ************************************************************************* //

View File

@ -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
// ************************************************************************* //