/* * Copyright 2009, 2010 Free Software Foundation, Inc. * * This software is distributed under the terms of the GNU Affero Public License. * See the COPYING file in the main directory for details. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ #include #include #include #include "Configuration.h" #include "Sockets.h" #include "Logger.h" #include "Timeval.h" using namespace std; // Reference to a global config table, used all over the system. extern ConfigurationTable gConfig; /** The global logging lock. */ static Mutex gLogLock; /**@ The global alarms table. */ //@{ Mutex alarmsLock; list alarmsList; void addAlarm(const string&); //@} /** Names of the logging levels. */ const char* levelNames[] = { "FORCE", "ERROR", "ALARM", "WARN", "NOTICE", "INFO", "DEBUG", "DEEPDEBUG" }; const unsigned numLevels = 8; ostream& operator<<(ostream& os, Log::Level level) { unsigned il = (unsigned)level; assert(il gGetLoggerAlarms() { alarmsLock.lock(); std::list ret; // excuse the "complexity", but to use std::copy with a list you need // an insert_iterator - copy technically overwrites, doesn't insert. std::insert_iterator< std::list > ii(ret, ret.begin()); std::copy(alarmsList.begin(), alarmsList.end(), ii); alarmsLock.unlock(); return ret; } // Add an alarm to the alarm list, and send it out via udp // // On the first call we read the ip and port from the configuration // TODO - is there any global setup function where this should be done? -- Alon void addAlarm(const string& s) { // Socket open and close on every alarm - wise? // Probably. That way we are sure to pick up changes in the target address. // Alarms should not happen often. if (gConfig.defines("Log.Alarms.TargetIP")) { UDPSocket alarmsocket(0, gConfig.getStr("Log.Alarms.TargetIP"), gConfig.getNum("Log.Alarms.TargetPort")); alarmsocket.write(s.c_str()); } // append to list and reduce list to max alarm count alarmsLock.lock(); alarmsList.push_back(s); unsigned maxAlarms = gConfig.getNum("Log.Alarms.Max"); while (alarmsList.size() > maxAlarms) alarmsList.pop_front(); alarmsLock.unlock(); } Log::~Log() { // XXX always handle alarms, even if the logging level is too low if (mReportLevel == LOG_ALARM) { addAlarm(mStream.str().c_str()); std::cerr << mStream.str() << std::endl; } // Current logging level was already checked by the macro. // So just log. gLogLock.lock(); mStream << std::endl; fprintf(gLoggingFile, "%s", mStream.str().c_str()); fflush(gLoggingFile); gLogLock.unlock(); } ostringstream& Log::get() { Timeval now; mStream.precision(4); mStream << now << ' ' << mReportLevel << ' '; return mStream; } void gLogInit(const char* defaultLevel) { // Define defaults in the global config if (!gConfig.defines("Log.Level")) { gConfig.set("Log.Level",defaultLevel); LOG(FORCE) << "Setting initial global logging level to " << defaultLevel; } if (!gConfig.defines("Log.Alarms.TargetPort")) { gConfig.set("Log.Alarms.TargetPort",DEFAULT_ALARM_PORT); } if (!gConfig.defines("Log.Alarms.Max")) { gConfig.set("Log.Alarms.Max",DEFAULT_MAX_ALARMS); } } // vim: ts=4 sw=4