FFmpegfs Fuse Multi Media Filesystem 2.16
logging.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2017 Original author K. Henriksson @n
3 * Copyright (C) 2017-2024 Norbert Schlia (nschlia@oblivion-software.de)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 *
19 * On Debian systems, the complete text of the GNU General Public License
20 * Version 3 can be found in `/usr/share/common-licenses/GPL-3'.
21 */
22
34#ifndef LOGGING_H
35#define LOGGING_H
36
37#pragma once
38
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#endif
42
43#include <map>
44#include <fstream>
45#include <sstream>
46#include <regex>
47#include <mutex>
48
80{
81public:
84 enum class LOGLEVEL
85 {
86 LOGERROR = 1,
87 LOGWARN = 2,
88 LOGINFO = 3,
89 LOGDEBUG = 4,
90 LOGTRACE = 5
91 };
92
101 explicit Logging(const std::string & logfile, LOGLEVEL max_level, bool to_stderr, bool to_syslog);
102
107 bool GetFail() const;
108
109private:
113 class Logger : public std::ostringstream
114 {
115 public:
121 Logger(LOGLEVEL loglevel, const std::string & filename) :
122 m_loglevel(loglevel),
123 m_filename(filename) {}
127 explicit Logger() :
132 virtual ~Logger();
133
134 private:
137 const std::string m_filename;
139 static const std::map<LOGLEVEL, int> m_syslog_level_map;
140 static const std::map<LOGLEVEL, std::string> m_level_name_map;
141 static const std::map<LOGLEVEL, std::string> m_level_colour_map;
142 };
143
144public:
154 static bool init_logging(const std::string & logfile, LOGLEVEL max_level, bool to_stderr, bool to_syslog);
155
162 template <typename T, typename... Args>
163 static void trace(const T filename, const std::string &format_string, Args &&...args)
164 {
165 LOGLEVEL loglevel = LOGLEVEL::LOGTRACE;
166
167 if (!show(loglevel))
168 {
169 return;
170 }
171
172 log_with_level(loglevel, filename, format_helper(format_string, 1, std::forward<Args>(args)...));
173 }
174
181 template <typename T, typename... Args>
182 static void debug(const T filename, const std::string &format_string, Args &&...args)
183 {
184 LOGLEVEL loglevel = LOGLEVEL::LOGDEBUG;
185
186 if (!show(loglevel))
187 {
188 return;
189 }
190
191 log_with_level(loglevel, filename, format_helper(format_string, 1, std::forward<Args>(args)...));
192 }
193
200 template <typename T, typename... Args>
201 static void info(const T filename, const std::string &format_string, Args &&...args)
202 {
203 LOGLEVEL loglevel = LOGLEVEL::LOGINFO;
204
205 if (!show(loglevel))
206 {
207 return;
208 }
209
210 log_with_level(loglevel, filename, format_helper(format_string, 1, std::forward<Args>(args)...));
211 }
212
219 template <typename T, typename... Args>
220 static void warning(const T filename, const std::string &format_string, Args &&...args)
221 {
222 LOGLEVEL loglevel = LOGLEVEL::LOGWARN;
223
224 if (!show(loglevel))
225 {
226 return;
227 }
228
229 log_with_level(loglevel, filename, format_helper(format_string, 1, std::forward<Args>(args)...));
230 }
231
238 template <typename T, typename... Args>
239 static void error(const T filename, const std::string &format_string, Args &&...args)
240 {
241 LOGLEVEL loglevel = LOGLEVEL::LOGERROR;
242
243 if (!show(loglevel))
244 {
245 return;
246 }
247
248 log_with_level(loglevel, filename, format_helper(format_string, 1, std::forward<Args>(args)...));
249 }
250
257 static void log_with_level(LOGLEVEL loglevel, const char *filename, const std::string & message);
258
265 static void log_with_level(LOGLEVEL loglevel, const std::string & filename, const std::string & message);
266
272 static bool show(LOGLEVEL loglevel)
273 {
274 return (m_logging && loglevel <= m_logging->m_max_level);
275 }
276
277private:
283 template<typename T>
284 static T & convert(T & val)
285 {
286 return val;
287 }
288
294 static std::string convert(const char * val)
295 {
296 if (val != nullptr)
297 {
298 return val;
299 }
300 else
301 {
302 return "(null)";
303 }
304 }
305
311 static std::string convert(char * val)
312 {
313 if (val != nullptr)
314 {
315 return val;
316 }
317 else
318 {
319 return "(null)";
320 }
321 }
322
323 // std::string cannot actually be passed to %s. That's how it works...
324
330 template<class T, typename std::enable_if<!std::is_same<T, std::string>::value, bool>::type = true>
331 static T & fix_std_string(T & val)
332 {
333 return val;
334 }
335
341 static const char * fix_std_string(const std::string & val)
342 {
343 return val.c_str();
344 }
345
352 static std::string format_helper(
353 const std::string &string_to_update,
354 const size_t __attribute__((unused)) index_to_replace);
355
367 template <typename T, typename... Args>
368 static std::string format_helper(
369 const std::string &string_to_search,
370 const size_t index_to_replace,
371 T &&val,
372 Args &&...args)
373 {
374 // Match %# exactly (e.g. %12 and %123 literally)
375
376 std::regex exp("%(<([^>]+)>)*" + std::to_string(index_to_replace) + "(?=[^0-9]|$)");
377 std::smatch res;
378 std::string string_to_update(string_to_search);
379 std::string::const_iterator searchStart(string_to_search.cbegin());
380 size_t offset = 0;
381
382 while (std::regex_search(searchStart, string_to_search.cend(), res, exp))
383 {
384 std::ostringstream ostr;
385
386 if (res[2].length())
387 {
388 // Found match with printf format in res[2]
389 std::vector<char> fmt;
390 std::string ftmspec = res[2].str();
391
392 if (ftmspec.front() != '%')
393 {
394 fmt.push_back('%');
395 }
396
397
398 fmt.insert(fmt.end(), ftmspec.begin(), ftmspec.end());
399 fmt.push_back('\0');
400
401 size_t size = static_cast<size_t>(std::snprintf(nullptr, 0, fmt.data(), fix_std_string(val))) + 1;
402 std::vector<char> buffer;
403 buffer.resize(size);
404 std::snprintf(buffer.data(), size, fmt.data(), fix_std_string(val));
405 ostr << buffer.data();
406 }
407 else
408 {
409 // No printf format, replace literally
410 ostr << convert(val);
411 }
412
413 string_to_update.replace(static_cast<size_t>(res.position()) + offset, static_cast<size_t>(res[0].length()), ostr.str());
414
415 offset += static_cast<size_t>(res.position()) + ostr.str().length();
416
417 searchStart = res.suffix().first;
418 }
419
420 return format_helper(
421 string_to_update,
422 index_to_replace + 1,
423 std::forward<Args>(args)...);
424 }
425
433 template <typename... Args>
434 static std::string format(const std::string &format_string, Args &&...args)
435 {
436 return format_helper(format_string, 1, std::forward<Args>(args)...);
437 }
438
439protected:
445 friend Logger Log(LOGLEVEL loglevel, const std::string & filename);
446 friend Logger;
448 static std::unique_ptr<Logging> m_logging;
449 static std::recursive_mutex m_mutex;
450 std::ofstream m_logfile;
452 const bool m_to_stderr;
453 const bool m_to_syslog;
454};
455
462#endif
Logging helper class.
Definition: logging.h:114
Logger()
Construct Logger object.
Definition: logging.h:127
const LOGLEVEL m_loglevel
Log level required to write log entry.
Definition: logging.h:135
const std::string m_filename
Name of file for which this log entry was written. May be empty.
Definition: logging.h:137
Logger(LOGLEVEL loglevel, const std::string &filename)
Construct Logger object.
Definition: logging.h:121
virtual ~Logger()
Destroy Logger object.
Definition: logging.cc:109
static const std::map< LOGLEVEL, int > m_syslog_level_map
Map our log levels to syslog levels.
Definition: logging.h:139
static const std::map< LOGLEVEL, std::string > m_level_name_map
Map log level enums to strings.
Definition: logging.h:140
static const std::map< LOGLEVEL, std::string > m_level_colour_map
Map log level enums to colours (logging to stderr only)
Definition: logging.h:141
Logging facility
Definition: logging.h:80
static std::string convert(char *val)
Convert char* to std::string.
Definition: logging.h:311
bool GetFail() const
Check whether either failbit or badbit is set.
Definition: logging.cc:200
static void log_with_level(LOGLEVEL loglevel, const char *filename, const std::string &message)
Write log entry.
Definition: logging.cc:226
static std::string format(const std::string &format_string, Args &&...args)
format string with single token
Definition: logging.h:434
static void warning(const T filename, const std::string &format_string, Args &&...args)
Write warning level log entry.
Definition: logging.h:220
friend Logger
Make logger class our friend.
Definition: logging.h:446
static bool init_logging(const std::string &logfile, LOGLEVEL max_level, bool to_stderr, bool to_syslog)
Initialise the logging facility.
Definition: logging.cc:210
static void debug(const T filename, const std::string &format_string, Args &&...args)
Write debug level log entry.
Definition: logging.h:182
static std::unique_ptr< Logging > m_logging
Reference to self, Logging is a singleton.
Definition: logging.h:448
static std::string format_helper(const std::string &string_to_update, const size_t __attribute__((unused)) index_to_replace)
Standard format_helper without parameters.
Definition: logging.cc:236
static std::string format_helper(const std::string &string_to_search, const size_t index_to_replace, T &&val, Args &&...args)
format_helper with variadic parameters.
Definition: logging.h:368
static T & convert(T &val)
Dummy: return orignal value unchanged.
Definition: logging.h:284
static std::string convert(const char *val)
Convert const char* to std::string.
Definition: logging.h:294
Logging(const std::string &logfile, LOGLEVEL max_level, bool to_stderr, bool to_syslog)
Definition: logging.cc:93
static T & fix_std_string(T &val)
Dummy: return orignal value unchanged if not type std::string.
Definition: logging.h:331
static void trace(const T filename, const std::string &format_string, Args &&...args)
Write trace level log entry.
Definition: logging.h:163
friend Logger Log(LOGLEVEL loglevel, const std::string &filename)
Make logger class our friend for our constructor.
Definition: logging.cc:205
std::ofstream m_logfile
Log file object for writing to disk.
Definition: logging.h:450
const LOGLEVEL m_max_level
The maximum level of log output to write.
Definition: logging.h:451
static std::recursive_mutex m_mutex
Access mutex.
Definition: logging.h:449
static void info(const T filename, const std::string &format_string, Args &&...args)
Write info level log entry.
Definition: logging.h:201
static bool show(LOGLEVEL loglevel)
Check if log entry should be displayed at the current log level.
Definition: logging.h:272
static void error(const T filename, const std::string &format_string, Args &&...args)
Write error level log entry.
Definition: logging.h:239
const bool m_to_stderr
Whether to write log output to stderr.
Definition: logging.h:452
static const char * fix_std_string(const std::string &val)
Convert std::string to const char*.
Definition: logging.h:341
const bool m_to_syslog
Whether to write log output to syslog.
Definition: logging.h:453
LOGLEVEL
Logging level types enum.
Definition: logging.h:85
@ LOGINFO
Info level.
@ LOGWARN
Warning level.
@ LOGDEBUG
Debug level.
@ LOGTRACE
Error level.
@ LOGERROR
Error level.
constexpr Logging::LOGLEVEL LOGDEBUG
Shorthand for log level DEBUG.
Definition: logging.h:459
constexpr Logging::LOGLEVEL LOGTRACE
Shorthand for log level TRACE.
Definition: logging.h:460
constexpr Logging::LOGLEVEL LOGWARN
Shorthand for log level WARNING.
Definition: logging.h:457
constexpr Logging::LOGLEVEL LOGERROR
Shorthand for log level ERROR.
Definition: logging.h:456
constexpr Logging::LOGLEVEL LOGINFO
Shorthand for log level INFO.
Definition: logging.h:458