blob: 36b76965ed0295be78950cad9b36c837fbd1e04e [file] [log] [blame]
dburgess82c46ff2011-10-07 02:40:51 +00001/*
2* Copyright 2009, 2010 Free Software Foundation, Inc.
3* Copyright 2010 Kestrel Signal Processing, Inc.
4*
5*
6* This software is distributed under the terms of the GNU Affero Public License.
7* See the COPYING file in the main directory for details.
8*
9* This use of this software may be subject to additional restrictions.
10* See the LEGAL file in the main directory for details.
11
12 This program is free software: you can redistribute it and/or modify
13 it under the terms of the GNU Affero General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU Affero General Public License for more details.
21
22 You should have received a copy of the GNU Affero General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
24
25*/
26
27#include <string.h>
28#include <cstdio>
29#include <fstream>
30#include <string>
kurtis.heimerl00913d72012-12-16 06:08:18 +000031#include <stdarg.h>
dburgess82c46ff2011-10-07 02:40:51 +000032
33#include "Configuration.h"
34#include "Logger.h"
35
36
37using namespace std;
38
39// Reference to a global config table, used all over the system.
40extern ConfigurationTable gConfig;
41
42
43/**@ The global alarms table. */
44//@{
45Mutex alarmsLock;
46list<string> alarmsList;
47void addAlarm(const string&);
48//@}
49
50
51
52
53/** Names of the logging levels. */
54const char *levelNames[] = {
55 "EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG"
56};
57int numLevels = 8;
58
59
60/** Given a string, return the corresponding level name. */
61int lookupLevel(const string& name)
62{
63 // Reverse search, since the numerically larger levels are more common.
64 for (int i=numLevels-1; i>=0; i--) {
65 if (name == levelNames[i]) return i;
66 }
67 // This should never be called with a bogus name.
68 LOG(ERR) << "undefined logging level " << name << "defaulting to ERR";
69 return LOG_ERR;
70}
71
72
73int getLoggingLevel(const char* filename)
74{
75 // Default level?
76 if (!filename) return lookupLevel(gConfig.getStr("Log.Level"));
77
78 // This can afford to be inefficient since it is not called that often.
79 const string keyName = string("Log.Level.") + string(filename);
80 if (gConfig.defines(keyName)) return lookupLevel(gConfig.getStr(keyName));
81 return lookupLevel(gConfig.getStr("Log.Level"));
82}
83
84
85
86int gGetLoggingLevel(const char* filename)
87{
88 // This is called a lot and needs to be efficient.
89
90 static Mutex sLogCacheLock;
91 static map<uint64_t,int> sLogCache;
92 static unsigned sCacheCount;
93 static const unsigned sCacheRefreshCount = 1000;
94
95 if (filename==NULL) return gGetLoggingLevel("");
96
97 HashString hs(filename);
98 uint64_t key = hs.hash();
99
100 sLogCacheLock.lock();
101 // Time for a cache flush?
102 if (sCacheCount>sCacheRefreshCount) {
103 sLogCache.clear();
104 sCacheCount=0;
105 }
106 // Is it cached already?
107 map<uint64_t,int>::const_iterator where = sLogCache.find(key);
108 sCacheCount++;
109 if (where!=sLogCache.end()) {
110 int retVal = where->second;
111 sLogCacheLock.unlock();
112 return retVal;
113 }
114 // Look it up in the config table and cache it.
115 // FIXME: Figure out why unlock and lock below fix the config table deadlock.
116 sLogCacheLock.unlock();
117 int level = getLoggingLevel(filename);
118 sLogCacheLock.lock();
119 sLogCache.insert(pair<uint64_t,int>(key,level));
120 sLogCacheLock.unlock();
121 return level;
122}
123
124
125
126
127
128// copies the alarm list and returns it. list supposed to be small.
129list<string> gGetLoggerAlarms()
130{
131 alarmsLock.lock();
132 list<string> ret;
133 // excuse the "complexity", but to use std::copy with a list you need
134 // an insert_iterator - copy technically overwrites, doesn't insert.
135 insert_iterator< list<string> > ii(ret, ret.begin());
136 copy(alarmsList.begin(), alarmsList.end(), ii);
137 alarmsLock.unlock();
138 return ret;
139}
140
141/** Add an alarm to the alarm list. */
142void addAlarm(const string& s)
143{
144 alarmsLock.lock();
145 alarmsList.push_back(s);
146 unsigned maxAlarms = gConfig.getNum("Log.Alarms.Max");
147 while (alarmsList.size() > maxAlarms) alarmsList.pop_front();
148 alarmsLock.unlock();
149}
150
151
152Log::~Log()
153{
dburgess7b2d5222011-11-20 00:22:41 +0000154 if (mDummyInit) return;
dburgess82c46ff2011-10-07 02:40:51 +0000155 // Anything at or above LOG_CRIT is an "alarm".
156 // Save alarms in the local list and echo them to stderr.
157 if (mPriority <= LOG_CRIT) {
158 addAlarm(mStream.str().c_str());
159 cerr << mStream.str() << endl;
160 }
161 // Current logging level was already checked by the macro.
162 // So just log.
163 syslog(mPriority, "%s", mStream.str().c_str());
164}
165
166
dburgess7b2d5222011-11-20 00:22:41 +0000167Log::Log(const char* name, const char* level, int facility)
168{
169 mDummyInit = true;
170 gLogInit(name, level, facility);
171}
172
173
dburgess82c46ff2011-10-07 02:40:51 +0000174ostringstream& Log::get()
175{
176 assert(mPriority<numLevels);
177 mStream << levelNames[mPriority] << ' ';
178 return mStream;
179}
180
181
182
183void gLogInit(const char* name, const char* level, int facility)
184{
185 // Set the level.
186 if (level) {
187 gConfig.set("Log.Level",level);
188 } else {
189 if (!gConfig.defines("Log.Level")) {
190 gConfig.set("Log.Level","WARNING");
191 }
192 }
193
194 // Define other logging parameters in the global config.
195 if (!gConfig.defines("Log.Alarms.Max")) {
196 gConfig.set("Log.Alarms.Max",DEFAULT_MAX_ALARMS);
197 }
198
199 // Open the log connection.
200 openlog(name,0,facility);
201}
202
203
kurtis.heimerl00913d72012-12-16 06:08:18 +0000204void gLogEarly(int level, const char *fmt, ...)
205{
206 va_list args;
207
208 va_start(args, fmt);
209 vsyslog(level | LOG_USER, fmt, args);
210 va_end(args);
211}
dburgess82c46ff2011-10-07 02:40:51 +0000212
213// vim: ts=4 sw=4