Fawkes API  Fawkes Development Version
fd_redirect.cpp
1 
2 /***************************************************************************
3  * fd_redirect.cpp - Redirect file descriptor writes to log
4  *
5  * Created: Thu Aug 21 15:03:37 2014
6  * Copyright 2014 Tim Niemueller [www.niemueller.de]
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version. A runtime exception applies to
13  * this software (see LICENSE.GPL_WRE file mentioned below for details).
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
21  */
22 
23 #include <logging/fd_redirect.h>
24 #include <logging/logger.h>
25 
26 #include <boost/bind.hpp>
27 
28 namespace fawkes {
29 
30 /** @class LogFileDescriptorToLog <logging/fd_redirect.h>
31  * Redirect a file descriptor to the log.
32  * This re-binds the file descriptor to a pipe, where it listens on the
33  * reading end and prints input to the logger. On destruction, it restores
34  * the original file descriptor (which is therefore not closed but re-bound.
35  * @author Tim Niemueller
36  */
37 
38 /** Constructor.
39  * @param fd file descriptor to redirect to the log
40  * @param logger logger to redirect to
41  * @param logname name to use as log component name
42  * @param log_level log level to log with
43  */
45  Logger * logger,
46  const char * logname,
47  Logger::LogLevel log_level)
48 : io_service_work_(io_service_),
49  stream_(io_service_),
50  logger_(logger),
51  log_name_(logname),
52  log_level_(log_level)
53 {
54  old_fd_ = fd;
55  old_fd_dup_ = dup(fd);
56  int log_pipe[2];
57  if (pipe(log_pipe) == -1) {
58  throw Exception(errno, "Failed to create log pipe");
59  }
60 
61  if (dup2(log_pipe[1], fd) == -1) {
62  throw Exception(errno, "Failed to dup2 pipe to fd");
63  }
64 
65  log_fd_ = dup(log_pipe[0]);
66  stream_.assign(log_fd_);
67 
68  // pipe fds have both been dup'ed
69  close(log_pipe[0]);
70  close(log_pipe[1]);
71 
72  io_service_thread_ = std::thread([this]() { this->io_service_.run(); });
73 
74  start_log(log_name_.c_str(), log_level_, stream_, buffer_);
75 }
76 
77 /** Destructor. */
79 {
80  io_service_.stop();
81  io_service_thread_.join();
82  // restore original file handle
83  dup2(old_fd_dup_, old_fd_);
84 
85  close(old_fd_dup_);
86  close(log_fd_);
87 }
88 
89 void
90 LogFileDescriptorToLog::start_log(const char * logname,
91  Logger::LogLevel log_level,
92  boost::asio::posix::stream_descriptor &sd,
93  boost::asio::streambuf & buf)
94 {
95  boost::asio::async_read_until(sd,
96  buf,
97  '\n',
98  boost::bind(&LogFileDescriptorToLog::handle_log_line,
99  this,
100  logname,
101  log_level,
102  boost::ref(sd),
103  boost::ref(buf),
104  boost::asio::placeholders::error,
105  boost::asio::placeholders::bytes_transferred));
106 }
107 
108 void
109 LogFileDescriptorToLog::handle_log_line(const char * logname,
110  Logger::LogLevel log_level,
111  boost::asio::posix::stream_descriptor &sd,
112  boost::asio::streambuf & buf,
113  boost::system::error_code ec,
114  size_t bytes_read)
115 {
116  if (ec) {
117  if (ec == boost::asio::error::eof) {
118  // stop logging
119  return;
120  } else {
121  logger_->log_error(logname,
122  "Failed to read log line %i (%s), continuing",
123  ec.value(),
124  ec.message().c_str());
125  }
126  } else {
127  std::string line;
128  std::istream in_stream(&buf);
129  std::getline(in_stream, line);
130  logger_->log(log_level, logname, "%s", line.c_str());
131  }
132  start_log(logname, log_level, sd, buf);
133 }
134 
135 } // end namespace fawkes
Base class for exceptions in Fawkes.
Definition: exception.h:36
LogFileDescriptorToLog(int fd, Logger *logger, const char *logname, Logger::LogLevel log_level)
Constructor.
Definition: fd_redirect.cpp:44
Interface for logging.
Definition: logger.h:42
virtual void log(LogLevel level, const char *component, const char *format,...)
Log message of given log level.
Definition: logger.cpp:326
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
LogLevel
Log level.
Definition: logger.h:51
Fawkes library namespace.