14 #include <boost/asio/read_until.hpp>
15 #include <boost/process/args.hpp>
16 #include <log4cplus/loggingmacros.h>
22 namespace bp = boost::process;
25 if (
auto pid = proc.
GetPid(); pid) {
26 os <<
'[' << *pid <<
']';
28 os <<
"[ <not running> ]";
38 : m_io_ctx(ctx), m_args(std::move(args)), m_stdout{ctx}, m_stderr{ctx} {
39 if (m_args.size() < 1) {
40 throw std::invalid_argument(
"No arguments provided");
42 m_args[0] = bp::search_path(m_args[0]).native();
49 assert(!m_proc.valid());
63 bp::std_out > m_stdout.pipe,
64 bp::std_err > m_stderr.pipe,
66 bp::on_exit = [
this](
int exit,
const std::error_code& ec_in) {
70 m_result = {exit, ec_in};
74 AsyncReadStream(m_stdout);
75 AsyncReadStream(m_stderr);
76 return m_promise.get_future();
79 std::error_code AsyncProcess::Abort() noexcept {
81 return std::make_error_code(std::errc::no_such_process);
89 std::optional<pid_t> AsyncProcess::GetPid() const noexcept {
96 std::error_code AsyncProcess::Signal(
int sig) noexcept {
98 return std::make_error_code(std::errc::no_such_process);
101 pid_t
id = m_proc.id();
102 int err = kill(
id, sig);
103 return std::make_error_code(
static_cast<std::errc
>(err));
106 bool AsyncProcess::IsRunning() const noexcept {
110 return m_proc.valid() && !m_result.has_value();
113 void AsyncProcess::AsyncReadStream(AsyncProcess::Pipe& pipe) {
115 boost::asio::async_read_until(pipe.pipe,
118 [
this, &pipe](
const boost::system::error_code& ec, std::size_t) {
126 std::istream is(&pipe.buffer);
127 std::string remaining(pipe.buffer.size(),
'\0');
128 is.read(remaining.data(), remaining.size());
129 pipe.signal(m_pid, remaining);
140 std::istream is(&pipe.buffer);
142 std::getline(is, line);
145 line.push_back(
'\n');
146 pipe.signal(m_pid, line);
148 AsyncReadStream(pipe);
152 void AsyncProcess::CheckCompleted() {
154 if (!m_result.has_value() || m_stdout.pipe.is_open() || m_stderr.pipe.is_open()) {
159 m_promise.set_exception(std::system_error(m_result->ec));
161 m_promise.set_value(m_result->exit_code);
165 LogCaptureLast::LogCaptureLast(log4cplus::Logger logger, std::size_t num_lines)
166 : m_logger(logger), m_buffer(num_lines) {
170 LOG4CPLUS_INFO(m_logger,
'[' << pid <<
"]: " <<
Trim(line));
171 m_buffer.push_back(line);
175 for (
auto const& line : lines.
Lines()) {
daq::AsyncProcess class definition
Interface to asynchronous process.
virtual std::vector< std::string > const & GetArguments() const noexcept=0
virtual std::optional< pid_t > GetPid() const noexcept=0
Get PID.
virtual ~AsyncProcess() noexcept
boost::future< int > Initiate() override
Starts process and asynchronous operations that read stdout and stderr.
AsyncProcess(boost::asio::io_context &ctx, std::vector< std::string > args)
Constructor.
Logs output to logger and keeps last N lines in circular buffer for later retrival.
void operator()(pid_t pid, std::string const &line) noexcept
auto Lines() const -> boost::circular_buffer< std::string >
Trim string from whitespace (' ', ' ')
Declaration of log4cplus helpers.
std::ostream & operator<<(std::ostream &os, AsyncProcessIf const &proc)
Formats proc representation in the form [<pid>] <args>