/*
* 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