Line data Source code
1 : // Copyright (c) 2013-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/snaplogger
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 : /** \file
21 : * \brief Variables are used to dynamically add parameters to log messages.
22 : *
23 : * This file declares the base variable class.
24 : *
25 : * The format defines \em functions which are written as in
26 : * `${function-name}`.
27 : *
28 : * Parameters can be passed to these functions by adding `:<param>`
29 : * to those definitions. These are named parameters and their default
30 : * value is "present" or not. A specific value can be assignd using
31 : * the equal sign as in `:param=<value>`.
32 : *
33 : * For example, the date function can be called as follow:
34 : *
35 : * \code
36 : * ${date:year:align=right:exact_width=2}
37 : * \endcode
38 : *
39 : * The `year` parameter is specific to the `date` function. The other
40 : * parameters are available whatever the function. This variable asks
41 : * to truncate the year to 2 character right aligned (i.e. "18" in
42 : * "2018".)
43 : *
44 : * In C, this would look something like:
45 : *
46 : * \code
47 : * date(FLAG_YEAR, ALIGN_RIGHT, 2);
48 : * \endcode
49 : */
50 :
51 :
52 : // self
53 : //
54 : #include "snaplogger/variable.h"
55 :
56 : #include "snaplogger/exception.h"
57 : #include "snaplogger/guard.h"
58 : #include "snaplogger/private_logger.h"
59 :
60 :
61 : // libutf8 lib
62 : //
63 : #include <libutf8/libutf8.h>
64 :
65 :
66 : // C++ lib
67 : //
68 : #include <iostream>
69 : #include <queue>
70 :
71 :
72 : // last include
73 : //
74 : #include <snapdev/poison.h>
75 :
76 :
77 :
78 : namespace snaplogger
79 : {
80 :
81 :
82 :
83 : namespace
84 : {
85 :
86 :
87 :
88 :
89 :
90 425 : DEFINE_LOGGER_VARIABLE(direct)
91 : {
92 123 : snap::NOTUSED(msg);
93 :
94 : // apply all our parameters as is
95 : //
96 246 : auto const & params(get_params());
97 246 : for(auto p : params)
98 : {
99 123 : value += p->get_value();
100 : }
101 :
102 : // do NOT apply parameters further, the user has no access to those
103 : // anyway; this is the direct text we find in between variables
104 : //
105 : //variable::process_value(msg, value);
106 123 : }
107 :
108 :
109 :
110 : }
111 : // no name namespace
112 :
113 :
114 :
115 : //////////////////////////////
116 : // PARAM
117 : //
118 :
119 194 : param::param(std::string const & name)
120 195 : : f_name(name)
121 : {
122 194 : if(f_name.empty())
123 : {
124 1 : throw invalid_parameter("a parameter must have a non-empty name.");
125 : }
126 193 : }
127 :
128 :
129 137 : std::string const & param::get_name() const
130 : {
131 137 : return f_name;
132 : }
133 :
134 :
135 20 : param::type_t param::get_type() const
136 : {
137 20 : return f_type;
138 : }
139 :
140 :
141 203 : std::string param::get_value() const
142 : {
143 203 : if(f_type != type_t::TYPE_STRING)
144 : {
145 : // TBD: we may instead want to return the integer as a string
146 : //
147 : throw invalid_parameter(
148 : "the ${...:"
149 2 : + f_name
150 3 : + "=<value>} parameter must be a valid string (not an integer).");
151 : }
152 202 : return f_value;
153 : }
154 :
155 :
156 154 : void param::set_value(std::string const & value)
157 : {
158 154 : f_value = value;
159 154 : f_type = type_t::TYPE_STRING;
160 154 : }
161 :
162 :
163 27 : int64_t param::get_integer() const
164 : {
165 27 : if(f_type != type_t::TYPE_INTEGER)
166 : {
167 : // TBD: we may want to check whether the string represents a valid
168 : // integer first and return that if so
169 : //
170 : throw invalid_parameter(
171 : "the ${...:"
172 2 : + f_name
173 3 : + "=<value>} parameter must be a valid integer.");
174 : }
175 26 : return f_integer;
176 : }
177 :
178 :
179 30 : void param::set_integer(std::int64_t integer)
180 : {
181 30 : f_integer = integer;
182 30 : f_type = type_t::TYPE_INTEGER;
183 30 : }
184 :
185 :
186 :
187 :
188 :
189 : //////////////////////////////
190 : // VARIABLE
191 : //
192 :
193 217 : variable::~variable()
194 : {
195 217 : }
196 :
197 :
198 0 : bool variable::ignore_on_no_repeat() const
199 : {
200 0 : return false;
201 : }
202 :
203 :
204 193 : void variable::add_param(param::pointer_t p)
205 : {
206 386 : guard g;
207 :
208 193 : f_params.push_back(p);
209 193 : }
210 :
211 :
212 188 : param::vector_t variable::get_params() const
213 : {
214 376 : guard g;
215 :
216 376 : return f_params;
217 : }
218 :
219 :
220 47392 : std::string variable::get_value(message const & msg) const
221 : {
222 94784 : guard g;
223 :
224 47392 : std::string value;
225 47392 : process_value(msg, value);
226 94774 : return value;
227 : }
228 :
229 :
230 47267 : void variable::process_value(message const & msg, std::string & value) const
231 : {
232 94534 : auto l(get_private_logger(msg));
233 :
234 : {
235 94534 : guard g;
236 :
237 47267 : if(!l->has_functions())
238 : {
239 : // no functions available, we're done
240 : return; // LCOV_EXCL_LINE
241 : }
242 : }
243 :
244 94534 : function_data d;
245 47267 : d.set_value(value);
246 :
247 47363 : for(auto p : f_params)
248 : {
249 96 : std::string const & name(p->get_name());
250 192 : auto func(l->get_function(name));
251 96 : if(func != nullptr)
252 : {
253 73 : func->apply(msg, d, p);
254 : }
255 : // else -- ignore missing functions
256 : }
257 :
258 47262 : value = libutf8::to_u8string(d.get_value());
259 : }
260 :
261 :
262 :
263 :
264 :
265 :
266 :
267 :
268 :
269 :
270 :
271 : //////////////////////////////
272 : // VARIABLE FACTORY
273 : //
274 :
275 61 : variable_factory::variable_factory(std::string const & type)
276 61 : : f_type(type)
277 : {
278 61 : }
279 :
280 :
281 61 : variable_factory::~variable_factory()
282 : {
283 61 : }
284 :
285 :
286 122 : std::string const & variable_factory::get_type() const
287 : {
288 122 : return f_type;
289 : }
290 :
291 :
292 :
293 :
294 61 : void register_variable_factory(variable_factory::pointer_t factory)
295 : {
296 62 : get_private_logger()->register_variable_factory(factory);
297 60 : }
298 :
299 :
300 :
301 218 : variable::pointer_t get_variable(std::string const & type)
302 : {
303 218 : return get_private_logger()->get_variable(type);
304 : }
305 :
306 :
307 :
308 :
309 :
310 :
311 :
312 : //////////////////////////////
313 : // FUNCTION DATA
314 : //
315 :
316 47267 : void function_data::set_value(std::string value)
317 : {
318 47267 : f_value = libutf8::to_u32string(value);
319 47267 : }
320 :
321 26 : void function_data::set_value(std::u32string value)
322 : {
323 26 : f_value = value;
324 26 : }
325 :
326 47321 : std::u32string & function_data::get_value()
327 : {
328 47321 : return f_value;
329 : }
330 :
331 16 : void function_data::set_param(std::string const & name, std::string const & value)
332 : {
333 16 : f_params[name] = libutf8::to_u32string(value);
334 16 : }
335 :
336 18 : void function_data::set_param(std::string const & name, std::u32string const & value)
337 : {
338 18 : f_params[name] = value;
339 18 : }
340 :
341 26 : std::u32string function_data::get_param(std::string const & name, std::u32string const & default_value)
342 : {
343 26 : auto it(f_params.find(name));
344 26 : if(it == f_params.end())
345 : {
346 1 : return default_value;
347 : }
348 25 : return it->second;
349 : }
350 :
351 :
352 :
353 :
354 :
355 : //////////////////////////////
356 : // FUNCTION
357 : //
358 :
359 23 : function::function(std::string const & function_name)
360 23 : : f_name(function_name)
361 : {
362 23 : }
363 :
364 :
365 23 : function::~function()
366 : {
367 23 : }
368 :
369 :
370 46 : std::string const & function::get_name() const
371 : {
372 46 : return f_name;
373 : }
374 :
375 :
376 :
377 23 : void register_function(function::pointer_t func)
378 : {
379 46 : guard g;
380 :
381 24 : get_private_logger()->register_function(func);
382 22 : }
383 :
384 :
385 :
386 :
387 6 : } // snaplogger namespace
388 : // vim: ts=4 sw=4 et
|