]> granicus.if.org Git - icinga2/blob - lib/base/logger.cpp
Merge pull request #7185 from Icinga/bugfix/gelfwriter-wrong-log-facility
[icinga2] / lib / base / logger.cpp
1 /* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */
2
3 #include "base/logger.hpp"
4 #include "base/logger-ti.cpp"
5 #include "base/application.hpp"
6 #include "base/streamlogger.hpp"
7 #include "base/configtype.hpp"
8 #include "base/utility.hpp"
9 #include "base/objectlock.hpp"
10 #include "base/context.hpp"
11 #include "base/scriptglobal.hpp"
12 #include <iostream>
13
14 using namespace icinga;
15
16 template Log& Log::operator<<(const Value&);
17 template Log& Log::operator<<(const String&);
18 template Log& Log::operator<<(const std::string&);
19 template Log& Log::operator<<(const bool&);
20 template Log& Log::operator<<(const unsigned int&);
21 template Log& Log::operator<<(const int&);
22 template Log& Log::operator<<(const unsigned long&);
23 template Log& Log::operator<<(const long&);
24 template Log& Log::operator<<(const double&);
25
26 REGISTER_TYPE(Logger);
27
28 std::set<Logger::Ptr> Logger::m_Loggers;
29 boost::mutex Logger::m_Mutex;
30 bool Logger::m_ConsoleLogEnabled = true;
31 bool Logger::m_TimestampEnabled = true;
32 LogSeverity Logger::m_ConsoleLogSeverity = LogInformation;
33
34 INITIALIZE_ONCE([]() {
35         ScriptGlobal::Set("System.LogDebug", LogDebug, true);
36         ScriptGlobal::Set("System.LogNotice", LogNotice, true);
37         ScriptGlobal::Set("System.LogInformation", LogInformation, true);
38         ScriptGlobal::Set("System.LogWarning", LogWarning, true);
39         ScriptGlobal::Set("System.LogCritical", LogCritical, true);
40 });
41
42 /**
43  * Constructor for the Logger class.
44  */
45 void Logger::Start(bool runtimeCreated)
46 {
47         ObjectImpl<Logger>::Start(runtimeCreated);
48
49         boost::mutex::scoped_lock lock(m_Mutex);
50         m_Loggers.insert(this);
51 }
52
53 void Logger::Stop(bool runtimeRemoved)
54 {
55         {
56                 boost::mutex::scoped_lock lock(m_Mutex);
57                 m_Loggers.erase(this);
58         }
59
60         ObjectImpl<Logger>::Stop(runtimeRemoved);
61 }
62
63 std::set<Logger::Ptr> Logger::GetLoggers()
64 {
65         boost::mutex::scoped_lock lock(m_Mutex);
66         return m_Loggers;
67 }
68
69 /**
70  * Retrieves the minimum severity for this logger.
71  *
72  * @returns The minimum severity.
73  */
74 LogSeverity Logger::GetMinSeverity() const
75 {
76         String severity = GetSeverity();
77         if (severity.IsEmpty())
78                 return LogInformation;
79         else {
80                 LogSeverity ls = LogInformation;
81
82                 try {
83                         ls = Logger::StringToSeverity(severity);
84                 } catch (const std::exception&) { /* use the default level */ }
85
86                 return ls;
87         }
88 }
89
90 /**
91  * Converts a severity enum value to a string.
92  *
93  * @param severity The severity value.
94  */
95 String Logger::SeverityToString(LogSeverity severity)
96 {
97         switch (severity) {
98                 case LogDebug:
99                         return "debug";
100                 case LogNotice:
101                         return "notice";
102                 case LogInformation:
103                         return "information";
104                 case LogWarning:
105                         return "warning";
106                 case LogCritical:
107                         return "critical";
108                 default:
109                         BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid severity."));
110         }
111 }
112
113 /**
114  * Converts a string to a severity enum value.
115  *
116  * @param severity The severity.
117  */
118 LogSeverity Logger::StringToSeverity(const String& severity)
119 {
120         if (severity == "debug")
121                 return LogDebug;
122         else if (severity == "notice")
123                 return LogNotice;
124         else if (severity == "information")
125                 return LogInformation;
126         else if (severity == "warning")
127                 return LogWarning;
128         else if (severity == "critical")
129                 return LogCritical;
130         else
131                 BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid severity: " + severity));
132 }
133
134 void Logger::DisableConsoleLog()
135 {
136         m_ConsoleLogEnabled = false;
137 }
138
139 void Logger::EnableConsoleLog()
140 {
141         m_ConsoleLogEnabled = true;
142 }
143
144 bool Logger::IsConsoleLogEnabled()
145 {
146         return m_ConsoleLogEnabled;
147 }
148
149 void Logger::SetConsoleLogSeverity(LogSeverity logSeverity)
150 {
151         m_ConsoleLogSeverity = logSeverity;
152 }
153
154 LogSeverity Logger::GetConsoleLogSeverity()
155 {
156         return m_ConsoleLogSeverity;
157 }
158
159 void Logger::DisableTimestamp()
160 {
161         m_TimestampEnabled = false;
162 }
163
164 void Logger::EnableTimestamp()
165 {
166         m_TimestampEnabled = true;
167 }
168
169 bool Logger::IsTimestampEnabled()
170 {
171         return m_TimestampEnabled;
172 }
173
174 void Logger::ValidateSeverity(const Lazy<String>& lvalue, const ValidationUtils& utils)
175 {
176         ObjectImpl<Logger>::ValidateSeverity(lvalue, utils);
177
178         try {
179                 StringToSeverity(lvalue());
180         } catch (...) {
181                 BOOST_THROW_EXCEPTION(ValidationError(this, { "severity" }, "Invalid severity specified: " + lvalue()));
182         }
183 }
184
185 Log::Log(LogSeverity severity, String facility, const String& message)
186         : m_Severity(severity), m_Facility(std::move(facility))
187 {
188         m_Buffer << message;
189 }
190
191 Log::Log(LogSeverity severity, String facility)
192         : m_Severity(severity), m_Facility(std::move(facility))
193 { }
194
195 /**
196  * Writes the message to the application's log.
197  */
198 Log::~Log()
199 {
200         LogEntry entry;
201         entry.Timestamp = Utility::GetTime();
202         entry.Severity = m_Severity;
203         entry.Facility = m_Facility;
204         entry.Message = m_Buffer.str();
205
206         if (m_Severity >= LogWarning) {
207                 ContextTrace context;
208
209                 if (context.GetLength() > 0) {
210                         std::ostringstream trace;
211                         trace << context;
212                         entry.Message += "\nContext:" + trace.str();
213                 }
214         }
215
216         for (const Logger::Ptr& logger : Logger::GetLoggers()) {
217                 ObjectLock llock(logger);
218
219                 if (!logger->IsActive())
220                         continue;
221
222                 if (entry.Severity >= logger->GetMinSeverity())
223                         logger->ProcessLogEntry(entry);
224
225 #ifdef I2_DEBUG /* I2_DEBUG */
226                 /* Always flush, don't depend on the timer. Enable this for development sprints. */
227                 //logger->Flush();
228 #endif /* I2_DEBUG */
229         }
230
231         if (Logger::IsConsoleLogEnabled() && entry.Severity >= Logger::GetConsoleLogSeverity()) {
232                 StreamLogger::ProcessLogEntry(std::cout, entry);
233
234                 /* "Console" might be a pipe/socket (systemd, daemontools, docker, ...),
235                  * then cout will not flush lines automatically. */
236                 std::cout << std::flush;
237         }
238 }
239
240 Log& Log::operator<<(const char *val)
241 {
242         m_Buffer << val;
243         return *this;
244 }