blob: ee607fdf9e99be969c30fc12af1a1470b1691f11 [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.
kurtis.heimerl5a872472013-05-31 21:47:25 +00004* Copyright 2011, 2012 Range Networks, Inc.
dburgess82c46ff2011-10-07 02:40:51 +00005*
6*
7* This software is distributed under the terms of the GNU Affero Public License.
8* See the COPYING file in the main directory for details.
9*
10* This use of this software may be subject to additional restrictions.
11* See the LEGAL file in the main directory for details.
12
13 This program is free software: you can redistribute it and/or modify
14 it under the terms of the GNU Affero General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU Affero General Public License for more details.
22
23 You should have received a copy of the GNU Affero General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
25
26*/
27
28#include <string.h>
29#include <cstdio>
30#include <fstream>
31#include <string>
kurtis.heimerl00913d72012-12-16 06:08:18 +000032#include <stdarg.h>
Alexander Chemeris4793f462017-03-17 18:35:48 -070033#include <sys/time.h> // For gettimeofday
dburgess82c46ff2011-10-07 02:40:51 +000034
dburgess82c46ff2011-10-07 02:40:51 +000035#include "Logger.h"
kurtis.heimerl5a872472013-05-31 21:47:25 +000036#include "Threads.h" // pat added
dburgess82c46ff2011-10-07 02:40:51 +000037
Pau Espin Pedrolddf47432018-01-09 13:25:38 +010038#define MAX_ALARMS 20
dburgess82c46ff2011-10-07 02:40:51 +000039
40using namespace std;
41
Alexander Chemerisa8cf2082015-07-30 20:04:18 -040042// Switches to enable/disable logging targets
Alexander Chemerisa8cf2082015-07-30 20:04:18 -040043bool gLogToConsole = true;
44bool gLogToSyslog = false;
45FILE *gLogToFile = NULL;
46Mutex gLogToLock;
47
Pau Espin Pedrolf3837d22018-01-09 14:49:33 +010048// Global log level threshold:
49int config_log_level;
dburgess82c46ff2011-10-07 02:40:51 +000050
51/**@ The global alarms table. */
52//@{
53Mutex alarmsLock;
54list<string> alarmsList;
55void addAlarm(const string&);
56//@}
57
58
59
kurtis.heimerl5a872472013-05-31 21:47:25 +000060// (pat) If Log messages are printed before the classes in this module are inited
61// (which happens when static classes have constructors that do work)
62// the OpenBTS just crashes.
63// Prevent that by setting sLoggerInited to true when this module is inited.
64static bool sLoggerInited = 0;
65static struct CheckLoggerInitStatus {
66 CheckLoggerInitStatus() { sLoggerInited = 1; }
67} sCheckloggerInitStatus;
68
69
dburgess82c46ff2011-10-07 02:40:51 +000070
71/** Names of the logging levels. */
72const char *levelNames[] = {
73 "EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG"
74};
75int numLevels = 8;
76
77
kurtis.heimerl5a872472013-05-31 21:47:25 +000078int levelStringToInt(const string& name)
dburgess82c46ff2011-10-07 02:40:51 +000079{
80 // Reverse search, since the numerically larger levels are more common.
81 for (int i=numLevels-1; i>=0; i--) {
82 if (name == levelNames[i]) return i;
83 }
kurtis.heimerl5a872472013-05-31 21:47:25 +000084
85 // Common substitutions.
86 if (name=="INFORMATION") return 6;
87 if (name=="WARN") return 4;
88 if (name=="ERROR") return 3;
89 if (name=="CRITICAL") return 2;
90 if (name=="EMERGENCY") return 0;
91
92 // Unknown level.
93 return -1;
94}
95
Alexander Chemeris4793f462017-03-17 18:35:48 -070096static std::string format(const char *fmt, ...)
97{
98 va_list ap;
99 char buf[300];
100 va_start(ap,fmt);
101 int n = vsnprintf(buf,300,fmt,ap);
102 va_end(ap);
103 if (n >= (300-4)) { strcpy(&buf[(300-4)],"..."); }
104 return std::string(buf);
105}
106
107const std::string timestr()
108{
109 struct timeval tv;
110 struct tm tm;
111 gettimeofday(&tv,NULL);
112 localtime_r(&tv.tv_sec,&tm);
113 unsigned tenths = tv.tv_usec / 100000; // Rounding down is ok.
114 return format(" %02d:%02d:%02d.%1d",tm.tm_hour,tm.tm_min,tm.tm_sec,tenths);
115}
116
117std::ostream& operator<<(std::ostream& os, std::ostringstream& ss)
118{
119 return os << ss.str();
120}
dburgess82c46ff2011-10-07 02:40:51 +0000121
dburgess82c46ff2011-10-07 02:40:51 +0000122// copies the alarm list and returns it. list supposed to be small.
123list<string> gGetLoggerAlarms()
124{
125 alarmsLock.lock();
126 list<string> ret;
127 // excuse the "complexity", but to use std::copy with a list you need
128 // an insert_iterator - copy technically overwrites, doesn't insert.
129 insert_iterator< list<string> > ii(ret, ret.begin());
130 copy(alarmsList.begin(), alarmsList.end(), ii);
131 alarmsLock.unlock();
132 return ret;
133}
134
135/** Add an alarm to the alarm list. */
136void addAlarm(const string& s)
137{
138 alarmsLock.lock();
139 alarmsList.push_back(s);
Pau Espin Pedrolddf47432018-01-09 13:25:38 +0100140 while (alarmsList.size() > MAX_ALARMS) alarmsList.pop_front();
dburgess82c46ff2011-10-07 02:40:51 +0000141 alarmsLock.unlock();
142}
143
144
145Log::~Log()
146{
dburgess7b2d5222011-11-20 00:22:41 +0000147 if (mDummyInit) return;
dburgess82c46ff2011-10-07 02:40:51 +0000148 // Anything at or above LOG_CRIT is an "alarm".
149 // Save alarms in the local list and echo them to stderr.
Alexander Chemeriscc6f79b2015-03-01 10:30:12 +0100150 if (mPriority <= LOG_ERR) {
kurtis.heimerl5a872472013-05-31 21:47:25 +0000151 if (sLoggerInited) addAlarm(mStream.str().c_str());
dburgess82c46ff2011-10-07 02:40:51 +0000152 cerr << mStream.str() << endl;
153 }
Alexander Chemeris57219202015-05-24 13:20:44 -0400154 // Current logging level was already checked by the macro. So just log.
155 // Log to syslog
156 if (gLogToSyslog) {
157 syslog(mPriority, "%s", mStream.str().c_str());
158 }
159 // Log to file and console
kurtis.heimerl5a872472013-05-31 21:47:25 +0000160 if (gLogToConsole||gLogToFile) {
161 int mlen = mStream.str().size();
162 int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
Alexander Chemeris909ffbf2015-06-04 00:09:29 -0400163 ScopedLock lock(gLogToLock);
kurtis.heimerl5a872472013-05-31 21:47:25 +0000164 if (gLogToConsole) {
165 // The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
166 // so just use std::cout.
167 std::cout << mStream.str();
168 if (neednl) std::cout<<"\n";
169 }
170 if (gLogToFile) {
171 fputs(mStream.str().c_str(),gLogToFile);
172 if (neednl) {fputc('\n',gLogToFile);}
173 fflush(gLogToFile);
174 }
kurtis.heimerl5a872472013-05-31 21:47:25 +0000175 }
dburgess82c46ff2011-10-07 02:40:51 +0000176}
177
178
dburgess7b2d5222011-11-20 00:22:41 +0000179Log::Log(const char* name, const char* level, int facility)
180{
181 mDummyInit = true;
182 gLogInit(name, level, facility);
183}
184
185
dburgess82c46ff2011-10-07 02:40:51 +0000186ostringstream& Log::get()
187{
188 assert(mPriority<numLevels);
189 mStream << levelNames[mPriority] << ' ';
190 return mStream;
191}
192
193
194
Pau Espin Pedrolf3837d22018-01-09 14:49:33 +0100195void gLogInit(const char* name, const char* level, int facility, char* fn)
dburgess82c46ff2011-10-07 02:40:51 +0000196{
kurtis.heimerl5a872472013-05-31 21:47:25 +0000197 // Set the level if one has been specified.
Pau Espin Pedrolf3837d22018-01-09 14:49:33 +0100198 if (level)
199 config_log_level = levelStringToInt(level);
dburgess82c46ff2011-10-07 02:40:51 +0000200
kurtis.heimerl5a872472013-05-31 21:47:25 +0000201 // Both the transceiver and OpenBTS use this same facility, but only OpenBTS/OpenNodeB may use this log file:
Pau Espin Pedrolf3837d22018-01-09 14:49:33 +0100202 if (!gLogToFile && fn) {
203 gLogToFile = fopen(fn,"w"); // New log file each time we start.
204 if (gLogToFile) {
205 time_t now;
206 time(&now);
207 fprintf(gLogToFile,"Starting at %s",ctime(&now));
208 fflush(gLogToFile);
209 std::cout << "Logging to file: " << fn << "\n";
kurtis.heimerl5a872472013-05-31 21:47:25 +0000210 }
dburgess82c46ff2011-10-07 02:40:51 +0000211 }
212
213 // Open the log connection.
214 openlog(name,0,facility);
215}
216
dburgess82c46ff2011-10-07 02:40:51 +0000217// vim: ts=4 sw=4