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/bind.hpp>
27
28namespace 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
89void
90LogFileDescriptorToLog::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
108void
109LogFileDescriptorToLog::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.