--- /dev/null
+/*
+ * Copyright (C) 2015 Canonical, Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <thread>
+
+#ifndef BOOST_LOG_DYN_LINK
+#define BOOST_LOG_DYN_LINK
+#endif
+#include <boost/date_time.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/log/expressions.hpp>
+#include <boost/log/support/date_time.hpp>
+#include <boost/log/trivial.hpp>
+#include <boost/log/utility/manipulators.hpp>
+#include <boost/log/utility/setup.hpp>
+#define BOOST_LOG_USE_NATIVE_SYSLOG
+#include <boost/log/sinks/syslog_backend.hpp>
+
+#include "anbox/logger.h"
+
+namespace {
+namespace attrs {
+BOOST_LOG_ATTRIBUTE_KEYWORD(Severity, "Severity", anbox::Logger::Severity)
+BOOST_LOG_ATTRIBUTE_KEYWORD(Location, "Location", anbox::Logger::Location)
+BOOST_LOG_ATTRIBUTE_KEYWORD(Timestamp, "Timestamp", boost::posix_time::ptime)
+}
+
+struct BoostLogLogger : public anbox::Logger {
+ BoostLogLogger() : initialized_(false) {}
+
+ void Init(const anbox::Logger::Severity& severity = anbox::Logger::Severity::kWarning) override {
+ if (initialized_)
+ return;
+
+ boost::log::formatter formatter =
+ boost::log::expressions::stream
+ << "[" << attrs::Severity << " "
+ << boost::log::expressions::format_date_time<boost::posix_time::ptime>(
+ "Timestamp", "%Y-%m-%d %H:%M:%S")
+ << "] "
+ << boost::log::expressions::if_(boost::log::expressions::has_attr(
+ attrs::Location))[boost::log::expressions::stream
+ << "[" << attrs::Location << "] "]
+ << boost::log::expressions::smessage;
+
+ boost::log::core::get()->remove_all_sinks();
+
+ // If we have a controlling tty then we use the console for log outpu
+ // and otherwise we move everything into the system syslog.
+ if (isatty(0)) {
+ auto logger = boost::log::add_console_log(std::cout);
+ logger->set_formatter(formatter);
+ } else {
+ boost::shared_ptr<boost::log::sinks::syslog_backend> backend(
+ new boost::log::sinks::syslog_backend(
+ boost::log::keywords::facility = boost::log::sinks::syslog::user,
+ boost::log::keywords::use_impl = boost::log::sinks::syslog::native));
+ backend->set_severity_mapper(boost::log::sinks::syslog::direct_severity_mapping<int>("Severity"));
+ boost::log::core::get()->add_sink(boost::make_shared<boost::log::sinks::synchronous_sink<
+ boost::log::sinks::syslog_backend>>(backend));
+ }
+
+ severity_ = severity;
+ initialized_ = true;
+ }
+
+ void SetSeverity(const Severity& severity) override {
+ severity_ = severity;
+ }
+
+ Severity GetSeverity() override {
+ return severity_;
+ }
+
+ void Log(Severity severity, const std::string& message, const boost::optional<Location>& loc) override {
+ if (!initialized_) Init();
+
+ // FIXME somehow set_filter doesn't work with the trivial logger. If
+ // we set a filter based on the severity attribute open_record will
+ // not return a new record. Because of that we do a poor man filtering
+ // here until we have a proper way to do this via boost.
+ if (severity < severity_)
+ return;
+
+ if (auto rec = boost::log::trivial::logger::get().open_record()) {
+ boost::log::record_ostream out{rec};
+ out << boost::log::add_value(attrs::Severity, severity)
+ << boost::log::add_value(attrs::Timestamp, boost::posix_time::microsec_clock::universal_time())
+ << message;
+
+ if (loc) {
+ // We have to pass in a temporary as boost::log (<= 1.55) expects a
+ // mutable reference to be passed to boost::log::add_value(...).
+ auto tmp = *loc;
+ out << boost::log::add_value(attrs::Location, tmp);
+ }
+
+ boost::log::trivial::logger::get().push_record(std::move(rec));
+ }
+ }
+
+ private:
+ Severity severity_;
+ bool initialized_;
+};
+
+std::shared_ptr<anbox::Logger>& MutableInstance() {
+ static std::shared_ptr<anbox::Logger> instance{new BoostLogLogger()};
+ return instance;
+}
+
+void SetInstance(const std::shared_ptr<anbox::Logger>& logger) {
+ MutableInstance() = logger;
+}
+}
+namespace anbox {
+
+bool Logger::SetSeverityFromString(const std::string& severity) {
+ if (severity == "trace")
+ SetSeverity(Severity::kTrace);
+ else if (severity == "debug")
+ SetSeverity(Severity::kDebug);
+ else if (severity == "info")
+ SetSeverity(Severity::kInfo);
+ else if (severity == "warning")
+ SetSeverity(Severity::kWarning);
+ else if (severity == "error")
+ SetSeverity(Severity::kError);
+ else if (severity == "fatal")
+ SetSeverity(Severity::kFatal);
+ else
+ return false;
+ return true;
+}
+
+void Logger::Trace(const std::string& message,
+ const boost::optional<Location>& location) {
+ Log(Severity::kTrace, message, location);
+}
+
+void Logger::Debug(const std::string& message,
+ const boost::optional<Location>& location) {
+ Log(Severity::kDebug, message, location);
+}
+
+void Logger::Info(const std::string& message,
+ const boost::optional<Location>& location) {
+ Log(Severity::kInfo, message, location);
+}
+
+void Logger::Warning(const std::string& message,
+ const boost::optional<Location>& location) {
+ Log(Severity::kWarning, message, location);
+}
+
+void Logger::Error(const std::string& message,
+ const boost::optional<Location>& location) {
+ Log(Severity::kError, message, location);
+}
+
+void Logger::Fatal(const std::string& message,
+ const boost::optional<Location>& location) {
+ Log(Severity::kFatal, message, location);
+}
+
+std::ostream& operator<<(std::ostream& strm, anbox::Logger::Severity severity) {
+ switch (severity) {
+ case anbox::Logger::Severity::kTrace:
+ return strm << "TT";
+ case anbox::Logger::Severity::kDebug:
+ return strm << "DD";
+ case anbox::Logger::Severity::kInfo:
+ return strm << "II";
+ case anbox::Logger::Severity::kWarning:
+ return strm << "WW";
+ case anbox::Logger::Severity::kError:
+ return strm << "EE";
+ case anbox::Logger::Severity::kFatal:
+ return strm << "FF";
+ default:
+ return strm << static_cast<unsigned int>(severity);
+ }
+}
+
+std::ostream& operator<<(std::ostream& out, const Logger::Location& location) {
+ return out << utils::string_format(
+ "%s:%d@%s",
+ boost::filesystem::path(location.file).filename().string(),
+ location.line, location.function);
+}
+
+Logger& Log() { return *MutableInstance(); }
+
+void SetLogger(const std::shared_ptr<Logger>& logger) { SetInstance(logger); }
+
+} // namespace anbox