2 * Copyright (C) 2015 Canonical, Ltd.
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #ifndef BOOST_LOG_DYN_LINK
21 #define BOOST_LOG_DYN_LINK
23 #include <boost/date_time.hpp>
24 #include <boost/filesystem.hpp>
25 #include <boost/log/expressions.hpp>
26 #include <boost/log/support/date_time.hpp>
27 #include <boost/log/trivial.hpp>
28 #include <boost/log/utility/manipulators.hpp>
29 #include <boost/log/utility/setup.hpp>
30 #define BOOST_LOG_USE_NATIVE_SYSLOG
31 #include <boost/log/sinks/syslog_backend.hpp>
33 #include "anbox/logger.h"
37 BOOST_LOG_ATTRIBUTE_KEYWORD(Severity, "Severity", anbox::Logger::Severity)
38 BOOST_LOG_ATTRIBUTE_KEYWORD(Location, "Location", anbox::Logger::Location)
39 BOOST_LOG_ATTRIBUTE_KEYWORD(Timestamp, "Timestamp", boost::posix_time::ptime)
42 struct BoostLogLogger : public anbox::Logger {
43 BoostLogLogger() : initialized_(false) {}
45 void Init(const anbox::Logger::Severity& severity = anbox::Logger::Severity::kWarning) override {
49 boost::log::formatter formatter =
50 boost::log::expressions::stream
51 << "[" << attrs::Severity << " "
52 << boost::log::expressions::format_date_time<boost::posix_time::ptime>(
53 "Timestamp", "%Y-%m-%d %H:%M:%S")
55 << boost::log::expressions::if_(boost::log::expressions::has_attr(
56 attrs::Location))[boost::log::expressions::stream
57 << "[" << attrs::Location << "] "]
58 << boost::log::expressions::smessage;
60 boost::log::core::get()->remove_all_sinks();
62 // If we have a controlling tty then we use the console for log outpu
63 // and otherwise we move everything into the system syslog.
65 auto logger = boost::log::add_console_log(std::cout);
66 logger->set_formatter(formatter);
68 boost::shared_ptr<boost::log::sinks::syslog_backend> backend(
69 new boost::log::sinks::syslog_backend(
70 boost::log::keywords::facility = boost::log::sinks::syslog::user,
71 boost::log::keywords::use_impl = boost::log::sinks::syslog::native));
72 backend->set_severity_mapper(boost::log::sinks::syslog::direct_severity_mapping<int>("Severity"));
73 boost::log::core::get()->add_sink(boost::make_shared<boost::log::sinks::synchronous_sink<
74 boost::log::sinks::syslog_backend>>(backend));
81 void SetSeverity(const Severity& severity) override {
85 Severity GetSeverity() override {
89 void Log(Severity severity, const std::string& message, const boost::optional<Location>& loc) override {
90 if (!initialized_) Init();
92 // FIXME somehow set_filter doesn't work with the trivial logger. If
93 // we set a filter based on the severity attribute open_record will
94 // not return a new record. Because of that we do a poor man filtering
95 // here until we have a proper way to do this via boost.
96 if (severity < severity_)
99 if (auto rec = boost::log::trivial::logger::get().open_record()) {
100 boost::log::record_ostream out{rec};
101 out << boost::log::add_value(attrs::Severity, severity)
102 << boost::log::add_value(attrs::Timestamp, boost::posix_time::microsec_clock::universal_time())
106 // We have to pass in a temporary as boost::log (<= 1.55) expects a
107 // mutable reference to be passed to boost::log::add_value(...).
109 out << boost::log::add_value(attrs::Location, tmp);
112 boost::log::trivial::logger::get().push_record(std::move(rec));
121 std::shared_ptr<anbox::Logger>& MutableInstance() {
122 static std::shared_ptr<anbox::Logger> instance{new BoostLogLogger()};
126 void SetInstance(const std::shared_ptr<anbox::Logger>& logger) {
127 MutableInstance() = logger;
132 bool Logger::SetSeverityFromString(const std::string& severity) {
133 if (severity == "trace")
134 SetSeverity(Severity::kTrace);
135 else if (severity == "debug")
136 SetSeverity(Severity::kDebug);
137 else if (severity == "info")
138 SetSeverity(Severity::kInfo);
139 else if (severity == "warning")
140 SetSeverity(Severity::kWarning);
141 else if (severity == "error")
142 SetSeverity(Severity::kError);
143 else if (severity == "fatal")
144 SetSeverity(Severity::kFatal);
150 void Logger::Trace(const std::string& message,
151 const boost::optional<Location>& location) {
152 Log(Severity::kTrace, message, location);
155 void Logger::Debug(const std::string& message,
156 const boost::optional<Location>& location) {
157 Log(Severity::kDebug, message, location);
160 void Logger::Info(const std::string& message,
161 const boost::optional<Location>& location) {
162 Log(Severity::kInfo, message, location);
165 void Logger::Warning(const std::string& message,
166 const boost::optional<Location>& location) {
167 Log(Severity::kWarning, message, location);
170 void Logger::Error(const std::string& message,
171 const boost::optional<Location>& location) {
172 Log(Severity::kError, message, location);
175 void Logger::Fatal(const std::string& message,
176 const boost::optional<Location>& location) {
177 Log(Severity::kFatal, message, location);
180 std::ostream& operator<<(std::ostream& strm, anbox::Logger::Severity severity) {
182 case anbox::Logger::Severity::kTrace:
184 case anbox::Logger::Severity::kDebug:
186 case anbox::Logger::Severity::kInfo:
188 case anbox::Logger::Severity::kWarning:
190 case anbox::Logger::Severity::kError:
192 case anbox::Logger::Severity::kFatal:
195 return strm << static_cast<unsigned int>(severity);
199 std::ostream& operator<<(std::ostream& out, const Logger::Location& location) {
200 return out << utils::string_format(
202 boost::filesystem::path(location.file).filename().string(),
203 location.line, location.function);
206 Logger& Log() { return *MutableInstance(); }
208 void SetLogger(const std::shared_ptr<Logger>& logger) { SetInstance(logger); }