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 #include <boost/bind.hpp>
26 
27 namespace fawkes {
28 #if 0 /* just to make Emacs auto-indent happy */
29 }
30 #endif
31 
32 /** @class LogFileDescriptorToLog <logging/fd_redirect.h>
33  * Redirect a file descriptor to the log.
34  * This re-binds the file descriptor to a pipe, where it listens on the
35  * reading end and prints input to the logger. On destruction, it restores
36  * the original file descriptor (which is therefore not closed but re-bound.
37  * @author Tim Niemueller
38  */
39 
40 /** Constructor.
41  * @param fd file descriptor to redirect to the log
42  * @param logger logger to redirect to
43  * @param logname name to use as log component name
44  * @param log_level log level to log with
45  */
47  const char *logname, Logger::LogLevel log_level)
48  : io_service_work_(io_service_), stream_(io_service_),
49  logger_(logger), log_name_(logname), log_level_(log_level)
50 {
51  old_fd_ = fd;
52  old_fd_dup_ = dup(fd);
53  int log_pipe[2];
54  if (pipe(log_pipe) == -1) {
55  throw Exception(errno, "Failed to create log pipe");
56  }
57 
58  if (dup2(log_pipe[1], fd) == -1) {
59  throw Exception(errno, "Failed to dup2 pipe to fd");
60  }
61 
62  log_fd_ = dup(log_pipe[0]);
63  stream_.assign(log_fd_);
64 
65  // pipe fds have both been dup'ed
66  close(log_pipe[0]);
67  close(log_pipe[1]);
68 
69  io_service_thread_ = std::thread([this]() { this->io_service_.run(); });
70 
71  start_log(log_name_.c_str(), log_level_, stream_, buffer_);
72 }
73 
74 
75 /** Destructor. */
77 {
78  io_service_.stop();
79  io_service_thread_.join();
80  // restore original file handle
81  dup2(old_fd_dup_, old_fd_);
82 
83  close(old_fd_dup_);
84  close(log_fd_);
85 }
86 
87 
88 void
89 LogFileDescriptorToLog::start_log(const char *logname, Logger::LogLevel log_level,
90  boost::asio::posix::stream_descriptor &sd, boost::asio::streambuf &buf)
91 {
92  boost::asio::async_read_until(sd, buf, '\n',
93  boost::bind(
94  &LogFileDescriptorToLog::handle_log_line, this,
95  logname, log_level, boost::ref(sd), boost::ref(buf),
96  boost::asio::placeholders::error,
97  boost::asio::placeholders::bytes_transferred
98  ));
99 }
100 
101 
102 void
103 LogFileDescriptorToLog::handle_log_line(const char *logname, Logger::LogLevel log_level,
104  boost::asio::posix::stream_descriptor &sd, boost::asio::streambuf &buf,
105  boost::system::error_code ec, size_t bytes_read)
106 {
107  if (ec) {
108  if (ec == boost::asio::error::eof) {
109  // stop logging
110  return;
111  } else {
112  logger_->log_error(logname, "Failed to read log line %i (%s), continuing", ec.value(),
113  ec.message().c_str());
114  }
115  } else {
116  std::string line;
117  std::istream in_stream(&buf);
118  std::getline(in_stream, line);
119  logger_->log(log_level, logname, "%s", line.c_str());
120  }
121  start_log(logname, log_level, sd, buf);
122 }
123 
124 
125 
126 } // end namespace fawkes
LogLevel
Log level.
Definition: logger.h:45
Fawkes library namespace.
~LogFileDescriptorToLog()
Destructor.
Definition: fd_redirect.cpp:76
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
LogFileDescriptorToLog(int fd, Logger *logger, const char *logname, Logger::LogLevel log_level)
Constructor.
Definition: fd_redirect.cpp:46
virtual void log(LogLevel level, const char *component, const char *format,...)
Log message of given log level.
Definition: logger.cpp:315
Interface for logging.
Definition: logger.h:34