/* * * Copyright (c) 2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include "qpid/log/posix/SinkOptions.h" #include "qpid/log/SinkOptions.h" #include "qpid/log/Logger.h" #include "qpid/log/OstreamOutput.h" #include "qpid/OptionsTemplates.h" #include "qpid/memory.h" #include "qpid/Exception.h" #include #include #include #include #include using std::string; using qpid::Exception; namespace qpid { template po::value_semantic* create_value(log::posix::SyslogFacility& val, const std::string& arg); namespace log { namespace posix { namespace { // SyslogFacilities maps from syslog values to the text equivalents. class SyslogFacilities { public: typedef std::map ByName; typedef std::map ByValue; SyslogFacilities() { struct NameValue { const char* name; int value; }; NameValue nameValue[] = { { "AUTH", LOG_AUTH }, #ifdef HAVE_LOG_AUTHPRIV { "AUTHPRIV", LOG_AUTHPRIV }, #endif { "CRON", LOG_CRON }, { "DAEMON", LOG_DAEMON }, #ifdef HAVE_LOG_FTP { "FTP", LOG_FTP }, #endif { "KERN", LOG_KERN }, { "LOCAL0", LOG_LOCAL0 }, { "LOCAL1", LOG_LOCAL1 }, { "LOCAL2", LOG_LOCAL2 }, { "LOCAL3", LOG_LOCAL3 }, { "LOCAL4", LOG_LOCAL4 }, { "LOCAL5", LOG_LOCAL5 }, { "LOCAL6", LOG_LOCAL6 }, { "LOCAL7", LOG_LOCAL7 }, { "LPR", LOG_LPR }, { "MAIL", LOG_MAIL }, { "NEWS", LOG_NEWS }, { "SYSLOG", LOG_SYSLOG }, { "USER", LOG_USER }, { "UUCP", LOG_UUCP } }; for (size_t i = 0; i < sizeof(nameValue)/sizeof(nameValue[0]); ++i) { byName.insert(ByName::value_type(nameValue[i].name, nameValue[i].value)); // Recognise with and without LOG_ prefix e.g.: AUTH and LOG_AUTH byName.insert(ByName::value_type(string("LOG_")+nameValue[i].name, nameValue[i].value)); byValue.insert(ByValue::value_type(nameValue[i].value, string("LOG_")+nameValue[i].name)); } } int value(const string& name) const { string key(name); std::transform(key.begin(), key.end(), key.begin(), ::toupper); ByName::const_iterator i = byName.find(key); if (i == byName.end()) throw Exception("Not a valid syslog facility: " + name); return i->second; } string name(int value) const { ByValue::const_iterator i = byValue.find(value); if (i == byValue.end()) throw Exception("Not a valid syslog value: " + boost::lexical_cast(value)); return i->second; } private: ByName byName; ByValue byValue; }; // 'priorities' maps qpid log levels to syslog priorities. They are in // order of qpid log levels and must map to: // "trace", "debug", "info", "notice", "warning", "error", "critical" static int priorities[qpid::log::LevelTraits::COUNT] = { LOG_DEBUG, LOG_DEBUG, LOG_INFO, LOG_NOTICE, LOG_WARNING, LOG_ERR, LOG_CRIT }; std::string basename(const std::string path) { size_t i = path.find_last_of('/'); return path.substr((i == std::string::npos) ? 0 : i+1); } } // namespace std::ostream& operator<<(std::ostream& o, const SyslogFacility& f) { return o << SyslogFacilities().name(f.value); } std::istream& operator>>(std::istream& i, SyslogFacility& f) { std::string name; i >> name; f.value = SyslogFacilities().value(name); return i; } class SyslogOutput : public qpid::log::Logger::Output { public: SyslogOutput(const std::string& logName, const SyslogFacility& logFacility) : name(logName), facility(logFacility.value) { ::openlog(name.c_str(), LOG_PID, facility); } virtual ~SyslogOutput() { ::closelog(); } virtual void log(const Statement& s, const std::string& m) { syslog(priorities[s.level], "%s", m.c_str()); } private: std::string name; int facility; }; SinkOptions::SinkOptions(const std::string& argv0) : qpid::log::SinkOptions(), logToStderr(true), logToStdout(false), logToSyslog(false), syslogName(basename(argv0)), syslogFacility(LOG_DAEMON) { addOptions() ("log-to-stderr", optValue(logToStderr, "yes|no"), "Send logging output to stderr") ("log-to-stdout", optValue(logToStdout, "yes|no"), "Send logging output to stdout") ("log-to-file", optValue(logFile, "FILE"), "Send log output to FILE.") ("log-to-syslog", optValue(logToSyslog, "yes|no"), "Send logging output to syslog;\n\tcustomize using --syslog-name and --syslog-facility") ("syslog-name", optValue(syslogName, "NAME"), "Name to use in syslog messages") ("syslog-facility", optValue(syslogFacility,"LOG_XXX"), "Facility to use in syslog messages") ; } qpid::log::SinkOptions& SinkOptions::operator=(const qpid::log::SinkOptions& rhs) { const SinkOptions *prhs = dynamic_cast(&rhs); if (this != prhs) { logToStderr = prhs->logToStderr; logToStdout = prhs->logToStdout; logToSyslog = prhs->logToSyslog; logFile = prhs->logFile; syslogName = prhs->syslogName; syslogFacility.value = prhs->syslogFacility.value; } return *this; } void SinkOptions::detached(void) { if (logToStderr && !logToStdout && !logToSyslog && logFile.empty()) { logToStderr = false; logToSyslog = true; } } // The Logger acting on these options calls setup() to request any // Sinks be set up and fed back to the logger. void SinkOptions::setup(qpid::log::Logger *logger) { if (logToStderr) logger->output(make_auto_ptr (new qpid::log::OstreamOutput(std::clog))); if (logToStdout) logger->output(make_auto_ptr (new qpid::log::OstreamOutput(std::cout))); if (logFile.length() > 0) logger->output(make_auto_ptr (new qpid::log::OstreamOutput(logFile))); if (logToSyslog) logger->output(make_auto_ptr (new SyslogOutput(syslogName, syslogFacility))); } } // namespace qpid::log::posix SinkOptions* SinkOptions::create(const std::string& argv0) { return new qpid::log::posix::SinkOptions (argv0); } }} // namespace qpid::log