KDSPDSetup
Small library to initialize spdlog loggers from a toml configuration file.
setup.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KDSpdSetup.
3 
4  SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5 
6  SPDX-License-Identifier: MIT
7 
8  Contact KDAB at <info@kdab.com> for commercial licensing options.
9 */
10 #include "setup.h"
11 
12 #include <iostream>
13 
14 using std::literals::string_literals::operator""s;
15 
16 namespace KDSPDSetup::setup {
17 
18 void handleMultipleFileSink(toml::string &&typeStr, toml::table &&sinkTable, spdlog::sink_ptr &sinkPtr, bool const &truncate)
19 {
20  auto baseFilename = sinkTable.at("base_filename").as_string();
21  auto maxFiles = (sinkTable.contains("max_files")) ? static_cast<uint16_t>(sinkTable.at("max_files").as_integer()) : uint16_t{ 0 };
22 
24  sinkPtr = details::genFromRotateStr(std::move(typeStr), std::move(sinkTable), std::move(baseFilename), maxFiles);
25  }
26 
27  else if (details::inTypelist(typeStr, details::dailyStrs)) {
28  sinkPtr = details::genFromDailyStr(std::move(typeStr), std::move(sinkTable), truncate, std::move(baseFilename), maxFiles);
29  }
30 }
31 
32 void handleTruncatableSink(toml::string &&typeStr, toml::table &&sinkTable, spdlog::sink_ptr &sinkPtr)
33 {
34  auto const truncate = (sinkTable.contains("truncate")) ? sinkTable.at("truncate").as_boolean() : false;
35 
36  if (details::inTypelist(typeStr, details::fileStrs)) {
37  sinkPtr = details::genFromFileStr(std::move(typeStr), std::move(sinkTable), truncate);
39  handleMultipleFileSink(std::move(typeStr), std::move(sinkTable), sinkPtr, truncate);
40  }
41 }
42 
43 void setupSink(toml::table &&sinkTable)
44 {
45  spdlog::sink_ptr sinkPtr;
46 
47  auto const name = sinkTable.at("name").as_string();
48  auto typeStr = sinkTable.at("type").as_string();
49 
50  bool ok = false;
52  if (details::inTypelist(typeStr, typeList)) {
53  ok = true;
54  break;
55  }
56  }
57 
58  if (!ok)
59  throw std::out_of_range("KDSPDSetup: sink type "s + typeStr.str + " is not valid"s);
60 
61  toml::string level = "";
62  if (sinkTable.contains("level")) {
63  level = sinkTable.at("level").as_string();
64  }
65 
68  handleTruncatableSink(std::move(typeStr), std::move(sinkTable), sinkPtr);
69  }
70 
72  sinkPtr = details::genFromNullOrStdStr(std::move(typeStr));
73  }
74 
75  else if (details::inTypelist(typeStr, details::linuxStrs)) {
76 #ifdef __linux__
77  sinkPtr = details::genFromLinuxStr(std::move(typeStr), std::move(sinkTable));
78 #else
79  return;
80 #endif
81  } else if (details::inTypelist(typeStr, details::winStrs)) {
82 #ifdef _WIN32
83  sinkPtr = details::genFromWinStr(std::move(typeStr));
84 #else
85  return;
86 #endif
87  }
88 
89  if (level != "") {
90  if (!details::levelMap.contains(level))
91  throw std::out_of_range("KDSPDSetup: level "s + level.str + " not found"s);
92 
93  sinkPtr->set_level(details::levelMap.at(level));
94  }
95 
96  details::SPDMaps::emplaceSinkMap(std::make_pair(name, sinkPtr));
97 }
98 
99 void setupSinks(toml::value const &data)
100 {
101  auto sinks = toml::find<std::vector<toml::table>>(data, "sink");
102 
103  for (auto &&sinkTable : sinks) {
104  setupSink(std::move(sinkTable));
105  }
106 }
107 
108 void setupPatterns(toml::value const &data)
109 {
110  if (data.contains("global_pattern")) {
111  auto const globalPattern = toml::find<toml::string>(data, "global_pattern");
112  spdlog::set_pattern(globalPattern);
113  }
114 
115  if (data.contains("pattern")) {
116  auto const patterns = toml::find<std::vector<toml::table>>(data, "pattern");
117 
118  for (auto &&patternTable : patterns) {
119  auto const name = patternTable.at("name").as_string();
120  auto const value = patternTable.at("value").as_string();
121 
122  details::SPDMaps::emplacePatternMap(std::make_pair(name, value));
123  }
124  }
125 }
126 
127 void setupThreadPools(toml::value const &data)
128 {
129  if (data.contains("global_thread_pool")) {
130  auto const globalThreadPool = toml::find(data, "global_thread_pool");
131 
132  auto const queueSize = toml::find<std::size_t>(globalThreadPool, "queue_size");
133  auto const numThreads = toml::find<std::size_t>(globalThreadPool, "num_threads");
134  spdlog::init_thread_pool(queueSize, numThreads);
135  }
136 
137  if (data.contains("thread_pool")) {
138  auto const threadPools = toml::find<std::vector<toml::table>>(data, "thread_pool");
139 
140  for (auto &&poolTable : threadPools) {
141  auto const name = poolTable.at("name").as_string();
142  auto const queueSize = static_cast<std::size_t>(poolTable.at("queue_size").as_integer());
143  auto const numThreads = static_cast<std::size_t>(poolTable.at("num_threads").as_integer());
144 
145  details::SPDMaps::emplaceThreadPoolMap(std::make_pair(name, std::make_pair(queueSize, numThreads)));
146  }
147  }
148 }
149 
150 void registerAsynchronousLogger(toml::table const &loggerTable, toml::string const &name, std::vector<spdlog::sink_ptr> const &sinkList,
151  toml::string const &pattern)
152 {
153  auto const threadPool = (loggerTable.contains("thread_pool")) ? loggerTable.at("thread_pool").as_string() : "";
154 
155  static std::shared_ptr<spdlog::details::thread_pool> threadPoolPtr;
156 
157  if (threadPool != "") {
158  if (!details::SPDMaps::threadPoolMap().contains(threadPool))
159  throw std::out_of_range("KDSPDSetup: threadpool "s + threadPool.str + " not found"s);
160 
161  auto const threadPoolPair = details::SPDMaps::threadPoolMap().at(threadPool);
162  auto const queueSize = threadPoolPair.first;
163  auto const numThreads = threadPoolPair.second;
164  threadPoolPtr = std::make_shared<spdlog::details::thread_pool>(queueSize, numThreads);
165  } else {
166  threadPoolPtr = spdlog::thread_pool();
167  }
168 
169  auto const overflowPolicy =
170  (loggerTable.contains("overflow_policy")) ? loggerTable.at("overflow_policy").as_string() : "block";
171 
172  if (!details::overflowMap.contains(overflowPolicy))
173  throw std::out_of_range("KDSPDSetup: overflow policy "s + overflowPolicy.str + " not found"s);
174 
175  auto logger = std::make_shared<spdlog::async_logger>(name, sinkList.begin(), sinkList.end(), std::move(threadPoolPtr),
176  details::overflowMap.at(overflowPolicy));
177 
178  if (pattern != "") {
179  logger->set_pattern(pattern);
180  }
181 
182  spdlog::register_logger(logger);
183 }
184 
185 void registerSynchronousLogger(toml::table const &loggerTable, toml::string const &name, std::vector<spdlog::sink_ptr> const &sinkList,
186  toml::string const &pattern)
187 {
188  auto logger = std::make_shared<spdlog::logger>(name, sinkList.cbegin(), sinkList.cend());
189  if (pattern != "") {
190  logger->set_pattern(static_cast<std::string>(pattern));
191  }
192 
193  if (loggerTable.contains("level")) {
194  auto const level = loggerTable.at("level").as_string();
195 
196  if (!details::levelMap.contains(level))
197  throw std::out_of_range("KDSPDSetup: level "s + level.str + " not found"s);
198 
199  logger->set_level(details::levelMap.at(level));
200  }
201 
202  spdlog::register_logger(logger);
203 }
204 
205 void setupLogger(toml::table const &loggerTable)
206 {
207  auto const name = loggerTable.at("name").as_string();
208  if (spdlog::get(name) != nullptr) {
209  return;
210  }
211 
212  auto const sinks = loggerTable.at("sinks").as_array();
213 
214  auto sinkList = std::vector<spdlog::sink_ptr>{};
215  for (auto &&sink : sinks) {
216  if (details::SPDMaps::sinkMap().contains(sink.as_string())) {
217  sinkList.emplace_back(details::SPDMaps::sinkMap().at(sink.as_string()));
218  } else {
219  // ignore sink instead of throwing, but notify that this happens
220  std::cerr << "KDSPDSetup: setting up logger " << name
221  << " - skipped sink " << sink.as_string().str << " as it was not found";
222  }
223  }
224 
225  std::string pattern = "";
226 
227  if (loggerTable.contains("pattern")) {
228  if (!details::SPDMaps::patternMap().contains(loggerTable.at("pattern").as_string()))
229  throw std::out_of_range("KDSPDSetup: pattern "s + loggerTable.at("pattern").as_string().str + " not found"s);
230 
231  pattern = details::SPDMaps::patternMap().at(loggerTable.at("pattern").as_string());
232  }
233 
234  auto const type = (loggerTable.contains("type")) ? loggerTable.at("type").as_string() : "";
235 
236  if (type == "async") {
237  registerAsynchronousLogger(loggerTable, name, sinkList, pattern);
238  } else {
239  registerSynchronousLogger(loggerTable, name, sinkList, pattern);
240  }
241 }
242 
243 void setupLoggers(toml::value const &data)
244 {
245  auto const loggers = toml::find<std::vector<toml::table>>(data, "logger");
246  for (auto &&loggerTable : loggers) {
247  setupLogger(loggerTable);
248  }
249 }
250 
251 } // namespace KDSPDSetup::setup
static void emplaceSinkMap(std::pair< toml::string, spdlog::sink_ptr > &&_pr)
Emplace a pair in the private member KDSPDSetup::details::SPDMaps::mSinkMap. This function is called ...
Definition: details.cpp:26
static auto sinkMap() -> std::map< toml::string, spdlog::sink_ptr > const &
Getter method for the private member KDSPDSetup::details::SPDMaps::mSinkMap. Used to index the map an...
Definition: details.cpp:14
static auto patternMap() -> std::map< toml::string, toml::string > const &
Getter method for the private member KDSPDSetup::details::SPDMaps::mPatternMap. Used to index the map...
Definition: details.cpp:18
static auto threadPoolMap() -> std::map< toml::string, std::pair< std::size_t, std::size_t >> const &
Getter method for the private member KDSPDSetup::details::SPDMaps::mThreadPoolMap....
Definition: details.cpp:22
static void emplaceThreadPoolMap(std::pair< toml::string, std::pair< std::size_t, std::size_t >> &&_pr)
Emplace a pair in the private member KDSPDSetup::details::SPDMaps::mThreadPoolMap....
Definition: details.cpp:34
static void emplacePatternMap(std::pair< toml::string, toml::string > &&_pr)
Emplace a pair in the private member KDSPDSetup::details::SPDMaps::mSinkMap. This function is called ...
Definition: details.cpp:30
static auto const linuxStrs
Vector of strings of spdlog syslog sink typenames. Used when matching a type string from a TOML table...
Definition: details.h:87
static auto const dailyStrs
Vector of strings of spdlog daily file sink typenames. Used when matching a type string from a TOML t...
Definition: details.h:73
static auto const nullStrs
Vector of strings of spdlog null sink typenames. Used when matching a type string from a TOML table t...
Definition: details.h:80
auto genFromDailyStr(toml::string &&typeStr, toml::table &&sinkTable, bool const &truncate, toml::string &&baseFilename, uint16_t const &maxFiles) -> spdlog::sink_ptr
Return the result of calling KDSPDSetup::details::createDailyFileSinkPtr with the correct template ar...
Definition: details.cpp:147
static auto const fileStrs
Vector of strings of spdlog basic file sink typenames. Used when matching a type string from a TOML t...
Definition: details.h:59
bool inTypelist(std::string const &typeStr, std::vector< std::string > const &strList)
Returns true if a string typeStr is present in a vector strList, and false if not....
Definition: details.cpp:39
static auto const rotateStrs
Vector of strings of spdlog rotating file sink typenames. Used when matching a type string from a TOM...
Definition: details.h:66
static auto const winStrs
Vector of strings of spdlog MSVC sink typenames. Used when matching a type string from a TOML table t...
Definition: details.h:94
static auto const overflowMap
A simple map associating strings of spdlog::async_overflow_policy names to the enums themselves....
Definition: details.h:118
auto genFromFileStr(toml::string &&typeStr, toml::table &&sinkTable, bool const &truncate) -> spdlog::sink_ptr
Return the result of calling KDSPDSetup::details::createFileSinkPtr with the correct template argumen...
Definition: details.cpp:122
auto genFromRotateStr(toml::string &&typeStr, toml::table &&sinkTable, toml::string &&baseFilename, std::size_t const &maxFiles) -> spdlog::sink_ptr
Return the result of calling KDSPDSetup::details::createRotatingFileSinkPtr with the correct template...
Definition: details.cpp:134
static auto const levelMap
A simple map associating strings of spdlog::level::level_enum names to the enums themselves....
Definition: details.h:101
auto genFromNullOrStdStr(toml::string &&typeStr) -> spdlog::sink_ptr
Return the result of calling KDSPDSetup::details::createStdoutSinkPtr with the correct template argum...
Definition: details.cpp:160
static auto const stdStrs
Vector of strings of spdlog standard output sink typenames. Used when matching a type string from a T...
Definition: details.h:48
This namespace contains the functions directly called by KDSPDSetup::setupFrom, along with helpers ca...
Definition: setup.cpp:16
void setupLoggers(toml::value const &data)
Using data read from a toml file, extract vector of tables representing every logger specified....
Definition: setup.cpp:243
void setupPatterns(toml::value const &data)
Using data read from a toml file, search for the key global_pattern. If it exists,...
Definition: setup.cpp:108
void setupLogger(toml::table const &loggerTable)
Given a table representation of a logger whose name is not already registered with spdlog,...
Definition: setup.cpp:205
void setupSink(toml::table &&sinkTable)
Given a table representation of a sink, creates an spdlog::sink_ptr, and evaluates the type of sink s...
Definition: setup.cpp:43
void registerSynchronousLogger(toml::table const &loggerTable, toml::string const &name, std::vector< spdlog::sink_ptr > const &sinkList, toml::string const &pattern)
Creates an std::shared_ptr<spdlog::logger> initialized with name and the sink pointers in sinklist,...
Definition: setup.cpp:185
void handleMultipleFileSink(toml::string &&typeStr, toml::table &&sinkTable, spdlog::sink_ptr &sinkPtr, bool const &truncate)
Helper function for setting up sinks that use multiple files. The function extracts values for base_f...
Definition: setup.cpp:18
void setupSinks(toml::value const &data)
Using data read from a toml file, extract vector of tables representing every sink specified....
Definition: setup.cpp:99
void setupThreadPools(toml::value const &data)
Using data read from a toml file, search for a table global_thread_pool, and initialize it with the s...
Definition: setup.cpp:127
void handleTruncatableSink(toml::string &&typeStr, toml::table &&sinkTable, spdlog::sink_ptr &sinkPtr)
Helper function for setting up file-based sinks that require a truncate argument in their constructor...
Definition: setup.cpp:32
void registerAsynchronousLogger(toml::table const &loggerTable, toml::string const &name, std::vector< spdlog::sink_ptr > const &sinkList, toml::string const &pattern)
Creates an std::shared_ptr<spdlog::async_logger> initialized with name, the sink pointers in sinklist...
Definition: setup.cpp:150