1 // Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
2 //
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License, version 2.0, as
5 // published by the Free Software Foundation.
6 //
7 // This program is also distributed with certain software (including
8 // but not limited to OpenSSL) that is licensed under separate terms,
9 // as designated in a particular file or component or in included license
10 // documentation. The authors of MySQL hereby grant you an
11 // additional permission to link the program and your derivative works
12 // with the separately licensed software that they have included with
13 // MySQL.
14 //
15 // Without limiting anything contained in the foregoing, this file,
16 // which is part of MySQL Server, is also subject to the
17 // Universal FOSS Exception, version 1.0, a copy of which can be found at
18 // http://oss.oracle.com/licenses/universal-foss-exception.
19 //
20 // This program is distributed in the hope that it will be useful, but
21 // WITHOUT ANY WARRANTY; without even the implied warranty of
22 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 // See the GNU General Public License, version 2.0, for more details.
24 //
25 // You should have received a copy of the GNU General Public License
26 // along with this program; if not, write to the Free Software Foundation, Inc.,
27 // 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28
29 /**
30 This defines built-in functions for use by logging services.
31 These helpers are organized into a number of APIs grouping
32 related functionality.
33
34 For documentation of the individual functions, see log_builtins.cc
35 */
36
37 #ifndef LOG_BUILTINS_H
38 #define LOG_BUILTINS_H
39
40 #include <mysql/components/component_implementation.h>
41 #include <mysql/components/my_service.h>
42 #include <mysql/components/service_implementation.h>
43 #include <mysql/components/services/log_shared.h>
44 #if defined(MYSQL_DYNAMIC_PLUGIN)
45 #include <mysql/service_plugin_registry.h>
46 #endif
47 #include <stdarg.h>
48 #include <stdio.h>
49
50 #include <my_compiler.h>
51 #if defined(MYSQL_SERVER) && !defined(MYSQL_DYNAMIC_PLUGIN)
52 #include "sql/log.h"
53 #endif
54
55 /**
56 Primitives for services to interact with the structured logger:
57 functions pertaining to log_line and log_item data
58 */
59 BEGIN_SERVICE_DEFINITION(log_builtins)
60 /**
61 See whether a type is wellknown.
62
63 @param t log item type to examine
64
65 @retval LOG_ITEM_TYPE_NOT_FOUND: key not found
66 @retval >0: index in array of wellknowns
67 */
68 DECLARE_METHOD(int, wellknown_by_type, (log_item_type t));
69
70 /**
71 See whether a string is a wellknown field name.
72
73 @param key potential key starts here
74 @param length length of the string to examine
75
76 @retval LOG_ITEM_TYPE_RESERVED: reserved, but not "wellknown" key
77 @retval LOG_ITEM_TYPE_NOT_FOUND: key not found
78 @retval >0: index in array of wellknowns
79 */
80 DECLARE_METHOD(int, wellknown_by_name, (const char *key, size_t length));
81
82 /**
83 Accessor: from a record describing a wellknown key, get its type
84
85 @param idx index in array of wellknowns, see log_item_wellknown_by_...()
86
87 @retval the log item type for the wellknown key
88 */
89 DECLARE_METHOD(log_item_type, wellknown_get_type, (uint idx));
90
91 /**
92 Accessor: from a record describing a wellknown key, get its name
93
94 @param idx index in array of wellknowns, see log_item_wellknown_by_...()
95
96 @retval name (NTBS)
97 */
98 DECLARE_METHOD(const char *, wellknown_get_name, (uint idx));
99
100 /**
101 Sanity check an item.
102 Certain log sinks have very low requirements with regard to the data
103 they receive; they write keys as strings, and then data according to
104 the item's class (string, integer, or float), formatted to the sink's
105 standards (e.g. JSON, XML, ...).
106 Code that has higher requirements can use this check to see whether
107 the given item is of a known type (whether generic or wellknown),
108 whether the given type and class agree, and whether in case of a
109 well-known type, the given key is correct for that type.
110 If your code generates items that don't pass this check, you should
111 probably go meditate on it.
112
113 @param li the log_item to check
114
115 @retval LOG_ITEM_OK no problems
116 @retval LOG_ITEM_TYPE_NOT_FOUND unknown item type
117 @retval LOG_ITEM_CLASS_MISMATCH item_class derived from type isn't
118 what's set on the item
119 @retval LOG_ITEM_KEY_MISMATCH class not generic, so key should
120 match wellknown
121 @retval LOG_ITEM_STRING_NULL class is string, pointer is nullptr
122 @retval LOG_ITEM_KEY_NULL no key set (this is legal e.g. on aux
123 items of filter rules, but should not
124 occur in a log_line, i.e., log_sinks are
125 within their rights to discard such items)
126 */
127 DECLARE_METHOD(int, item_inconsistent, (log_item * li));
128
129 // helpers: predicates to find out about types and classes
130
131 /**
132 Predicate used to determine whether a type is generic
133 (generic string, generic float, generic integer) rather
134 than a well-known type.
135
136 @param t log item type to examine
137
138 @retval true if generic type
139 @retval false if wellknown type
140 */
141 DECLARE_METHOD(bool, item_generic_type, (log_item_type t));
142
143 /**
144 Predicate used to determine whether a class is a string
145 class (C-string or Lex-string).
146
147 @param c log item class to examine
148
149 @retval true if of a string class
150 @retval false if not of a string class
151 */
152 DECLARE_METHOD(bool, item_string_class, (log_item_class c));
153
154 /**
155 Predicate used to determine whether a class is a numeric
156 class (integer or float).
157
158 @param c log item class to examine
159
160 @retval true if of a numeric class
161 @retval false if not of a numeric class
162 */
163 DECLARE_METHOD(bool, item_numeric_class, (log_item_class c));
164
165 /**
166 Set an integer value on a log_item.
167 Fails gracefully if not log_item_data is supplied, so it can safely
168 wrap log_line_item_set[_with_key]().
169
170 @param lid log_item_data struct to set the value on
171 @param i integer to set
172
173 @retval true lid was nullptr (possibly: OOM, could not set up log_item)
174 @retval false all's well
175 */
176 DECLARE_METHOD(bool, item_set_int, (log_item_data * lid, longlong i));
177 /**
178 Set a floating point value on a log_item.
179 Fails gracefully if not log_item_data is supplied, so it can safely
180 wrap log_line_item_set[_with_key]().
181
182 @param lid log_item_data struct to set the value on
183 @param f float to set
184
185 @retval true lid was nullptr (possibly: OOM, could not set up log_item)
186 @retval false all's well
187 */
188 DECLARE_METHOD(bool, item_set_float, (log_item_data * lid, double f));
189
190 /**
191 Set a string value on a log_item.
192 Fails gracefully if not log_item_data is supplied, so it can safely
193 wrap log_line_item_set[_with_key]().
194
195 @param lid log_item_data struct to set the value on
196 @param s pointer to string
197 @param s_len length of string
198
199 @retval true lid was nullptr (possibly: OOM, could not set up log_item)
200 @retval false all's well
201 */
202 DECLARE_METHOD(bool, item_set_lexstring,
203 (log_item_data * lid, const char *s, size_t s_len));
204
205 /**
206 Set a string value on a log_item.
207 Fails gracefully if not log_item_data is supplied, so it can safely
208 wrap log_line_item_set[_with_key]().
209
210 @param lid log_item_data struct to set the value on
211 @param s pointer to NTBS
212
213 @retval true lid was nullptr (possibly: OOM, could not set up log_item)
214 @retval false all's well
215 */
216 DECLARE_METHOD(bool, item_set_cstring, (log_item_data * lid, const char *s));
217
218 /**
219 Create new log item with key name "key", and allocation flags of
220 "alloc" (see enum_log_item_free).
221 Will return a pointer to the item's log_item_data struct for
222 convenience.
223 This is mostly interesting for filters and other services that create
224 items that are not part of a log_line; sources etc. that intend to
225 create an item for a log_line (the more common case) should usually
226 use the below line_item_set_with_key() which creates an item (like
227 this function does), but also correctly inserts it into a log_line.
228
229 @param li the log_item to work on
230 @param t the item-type
231 @param key the key to set on the item.
232 ignored for non-generic types (may pass nullptr for those)
233 see alloc
234 @param alloc LOG_ITEM_FREE_KEY if key was allocated by caller
235 LOG_ITEM_FREE_NONE if key was not allocated
236 Allocated keys will automatically free()d when the
237 log_item is.
238 The log_item's alloc flags will be set to the
239 submitted value; specifically, any pre-existing
240 value will be clobbered. It is therefore WRONG
241 a) to use this on a log_item that already has a key;
242 it should only be used on freshly init'd log_items;
243 b) to use this on a log_item that already has a
244 value (specifically, an allocated one); the correct
245 order is to init a log_item, then set up type and
246 key, and finally to set the value. If said value is
247 an allocated string, the log_item's alloc should be
248 bitwise or'd with LOG_ITEM_FREE_VALUE.
249
250 @retval a pointer to the log_item's log_data, for easy chaining:
251 log_item_set_with_key(...)->data_integer= 1;
252 */
253 DECLARE_METHOD(log_item_data *, item_set_with_key,
254 (log_item * li, log_item_type t, const char *key, uint32 alloc));
255
256 /**
257 As log_item_set_with_key(), except that the key is automatically
258 derived from the wellknown log_item_type t.
259
260 Create new log item with type "t".
261 Will return a pointer to the item's log_item_data struct for
262 convenience.
263 This is mostly interesting for filters and other services that create
264 items that are not part of a log_line; sources etc. that intend to
265 create an item for a log_line (the more common case) should usually
266 use the below line_item_set_with_key() which creates an item (like
267 this function does), but also correctly inserts it into a log_line.
268
269 The allocation of this item will be LOG_ITEM_FREE_NONE;
270 specifically, any pre-existing value will be clobbered.
271 It is therefore WRONG
272 a) to use this on a log_item that already has a key;
273 it should only be used on freshly init'd log_items;
274 b) to use this on a log_item that already has a
275 value (specifically, an allocated one); the correct
276 order is to init a log_item, then set up type and
277 key, and finally to set the value. If said value is
278 an allocated string, the log_item's alloc should be
279 bitwise or'd with LOG_ITEM_FREE_VALUE.
280
281 @param li the log_item to work on
282 @param t the item-type
283
284 @retval a pointer to the log_item's log_data, for easy chaining:
285 log_item_set_with_key(...)->data_integer= 1;
286 */
287 DECLARE_METHOD(log_item_data *, item_set, (log_item * li, log_item_type t));
288
289 /**
290 Create new log item in log line "ll", with key name "key", and
291 allocation flags of "alloc" (see enum_log_item_free).
292 On success, the number of registered items on the log line is increased,
293 the item's type is added to the log_line's "seen" property,
294 and a pointer to the item's log_item_data struct is returned for
295 convenience.
296
297 @param ll the log_line to work on
298 @param t the item-type
299 @param key the key to set on the item.
300 ignored for non-generic types (may pass nullptr for those)
301 see alloc
302 @param alloc LOG_ITEM_FREE_KEY if key was allocated by caller
303 LOG_ITEM_FREE_NONE if key was not allocated
304 Allocated keys will automatically free()d when the
305 log_item is.
306 The log_item's alloc flags will be set to the
307 submitted value; specifically, any pre-existing
308 value will be clobbered. It is therefore WRONG
309 a) to use this on a log_item that already has a key;
310 it should only be used on freshly init'd log_items;
311 b) to use this on a log_item that already has a
312 value (specifically, an allocated one); the correct
313 order is to init a log_item, then set up type and
314 key, and finally to set the value. If said value is
315 an allocated string, the log_item's alloc should be
316 bitwise or'd with LOG_ITEM_FREE_VALUE.
317
318 @retval a pointer to the log_item's log_data, for easy chaining:
319 log_line_item_set_with_key(...)->data_integer= 1;
320 */
321 DECLARE_METHOD(log_item_data *, line_item_set_with_key,
322 (log_line * ll, log_item_type t, const char *key, uint32 alloc));
323
324 /**
325 Create a new log item of well-known type "t" in log line "ll".
326 On success, the number of registered items on the log line is increased,
327 the item's type is added to the log_line's "seen" property,
328 and a pointer to the item's log_item_data struct is returned for
329 convenience.
330
331 The allocation of this item will be LOG_ITEM_FREE_NONE;
332 specifically, any pre-existing value will be clobbered.
333 It is therefore WRONG
334 a) to use this on a log_item that already has a key;
335 it should only be used on freshly init'd log_items;
336 b) to use this on a log_item that already has a
337 value (specifically, an allocated one); the correct
338 order is to init a log_item, then set up type and
339 key, and finally to set the value. If said value is
340 an allocated string, the log_item's alloc should be
341 bitwise or'd with LOG_ITEM_FREE_VALUE.
342
343 @param ll the log_line to work on
344 @param t the item-type
345
346 @retval a pointer to the log_item's log_data, for easy chaining:
347 log_line_item_set_with_key(...)->data_integer= 1;
348 */
349 DECLARE_METHOD(log_item_data *, line_item_set,
350 (log_line * ll, log_item_type t));
351
352 /**
353 Dynamically allocate and initialize a log_line.
354
355 @retval nullptr could not set up buffer (too small?)
356 @retval other address of the newly initialized log_line
357 */
358 DECLARE_METHOD(log_line *, line_init, ());
359
360 /**
361 Release a log_line allocated with line_init()
362
363 @param ll a log_line previously allocated with line_init()
364 */
365 DECLARE_METHOD(void, line_exit, (log_line * ll));
366
367 /**
368 How many items are currently set on the given log_line?
369
370 @param ll the log-line to examine
371
372 @retval the number of items set
373 */
374 DECLARE_METHOD(int, line_item_count, (log_line * ll));
375
376 /**
377 Test whether a given type is presumed present on the log line.
378
379 @param ll the log_line to examine
380 @param m the log_type to test for
381
382 @retval 0 not present
383 @retval !=0 present
384 */
385 DECLARE_METHOD(log_item_type_mask, line_item_types_seen,
386 (log_line * ll, log_item_type_mask m));
387
388 /**
389 Get an iterator for the items in a log_line.
390 For now, only one iterator may exist per log_line.
391
392 @param ll the log_line to examine
393
394 @retval a log_iterm_iter, or nullptr on failure
395 */
396 DECLARE_METHOD(log_item_iter *, line_item_iter_acquire, (log_line * ll));
397
398 /**
399 Release an iterator for the items in a log_line.
400
401 @param it the iterator to release
402 */
403 DECLARE_METHOD(void, line_item_iter_release, (log_item_iter * it));
404 /**
405 Use the log_line iterator to get the first item from the set.
406
407 @param it the iterator to use
408
409 @retval pointer to the first log_item in the collection, or nullptr
410 */
411 DECLARE_METHOD(log_item *, line_item_iter_first, (log_item_iter * it));
412
413 /**
414 Use the log_line iterator to get the next item from the set.
415
416 @param it the iterator to use
417
418 @retval pointer to the next log_item in the collection, or nullptr
419 */
420 DECLARE_METHOD(log_item *, line_item_iter_next, (log_item_iter * it));
421
422 /**
423 Use the log_line iterator to get the current item from the set.
424
425 @param it the iterator to use
426
427 @retval pointer to the current log_item in the collection, or nullptr
428 */
429 DECLARE_METHOD(log_item *, line_item_iter_current, (log_item_iter * it));
430
431 /**
432 Complete, filter, and write submitted log items.
433
434 This expects a log_line collection of log-related key/value pairs,
435 e.g. from log_message().
436
437 Where missing, timestamp, priority, thread-ID (if any) and so forth
438 are added.
439
440 Log item source services, log item filters, and log item sinks are
441 then called; then all applicable resources are freed.
442
443 This interface is intended to facilitate the building of submission
444 interfaces other than the variadic message() one below. See the
445 example fluent C++ LogEvent() wrapper for an example of how to leverage
446 it.
447
448 @param ll key/value pairs describing info to log
449
450 @retval int number of fields in created log line
451 */
452 DECLARE_METHOD(int, line_submit, (log_line * ll));
453
454 /**
455 Submit a log-message for log "log_type".
456 Variadic convenience function for logging.
457
458 This fills in the array that is used by the filter and log-writer
459 services. Where missing, timestamp, priority, and thread-ID (if any)
460 are added. Log item source services, log item filters, and log item
461 writers are called.
462
463
464 The variadic list accepts a list of "assignments" of the form
465 - log_item_type, value, for well-known types, and
466 - log_item_type, key, value, for ad-hoc types (LOG_ITEM_GEN_*)
467
468 As its last item, the list should have
469 - an element of type LOG_ITEM_LOG_MESSAGE, containing a printf-style
470 format string, followed by all variables necessary to satisfy the
471 substitutions in that string
472
473 OR
474
475 - an element of type LOG_ITEM_LOG_LOOKUP, containing a MySQL error code,
476 which will be looked up in the list or regular error messages, followed
477 by all variables necessary to satisfy the substitutions in that string
478
479 OR
480
481 - an element of type LOG_ITEM_LOG_VERBATIM, containing a string that will
482 be used directly, with no % substitutions
483
484 see log_vmessage() for more information.
485 */
486 DECLARE_METHOD(int, message, (int log_type, ...));
487
488 /**
489 Escape \0 bytes, add \0 terminator. For log-writers and other sinks
490 that terminate in an API using C-strings.
491
492
493 @param li list_item to process
494
495 @retval -1 out of memory
496 @retval 0 success
497 */
498 DECLARE_METHOD(int, sanitize, (log_item * li));
499
500 /**
501 Return MySQL error message for a given error code.
502
503 @param mysql_errcode the error code the message for which to look up
504
505 @retval the message (a printf-style format string)
506 */
507 DECLARE_METHOD(const char *, errmsg_by_errcode, (int mysql_errcode));
508
509 /**
510 Return MySQL error code for a given error symbol.
511
512 @param sym the symbol to look up
513
514 @retval -1 failure
515 @retval >=0 the MySQL error code
516 */
517 DECLARE_METHOD(longlong, errcode_by_errsymbol, (const char *sym));
518
519 /**
520 Convenience function: Derive a log label ("error", "warning",
521 "information") from a severity.
522
523 @param prio the severity/prio in question
524
525 @return a label corresponding to that priority.
526 @retval "System" for prio of SYSTEM_LEVEL
527 @retval "Error" for prio of ERROR_LEVEL
528 @retval "Warning" for prio of WARNING_LEVEL
529 @retval "Note" for prio of INFORMATION_LEVEL
530 */
531 DECLARE_METHOD(const char *, label_from_prio, (int prio));
532
533 /**
534 open an error log file
535
536 @param file if beginning with '.':
537 @@global.log_error, except with this extension
538 otherwise:
539 use this as file name in the same location as
540 @@global.log_error
541
542 Value not contain folder separators!
543
544 @param[out] my_errstream an error log handle, or nullptr on failure
545
546 @retval 0 success
547 @retval !0 failure
548 */
549 DECLARE_METHOD(int, open_errstream, (const char *file, void **my_errstream));
550
551 /**
552 write to an error log file previously opened with open_errstream()
553
554 @param my_errstream a handle describing the log file
555 @param buffer pointer to the string to write
556 @param length length of the string to write
557
558 @retval 0 success
559 @retval !0 failure
560 */
561 DECLARE_METHOD(int, write_errstream,
562 (void *my_errstream, const char *buffer, size_t length));
563
564 /**
565 are we writing to a dedicated errstream, or are we sharing it?
566
567 @param my_errstream a handle describing the log file
568
569 @retval 0 not dedicated (multiplexed, stderr, ...)
570 @retval 1 dedicated
571 */
572 DECLARE_METHOD(int, dedicated_errstream, (void *my_errstream));
573
574 /**
575 close an error log file previously opened with open_errstream()
576
577 @param my_stream a handle describing the log file
578
579 @retval 0 success
580 @retval !0 failure
581 */
582 DECLARE_METHOD(int, close_errstream, (void **my_errstream));
583
584 END_SERVICE_DEFINITION(log_builtins)
585
586 /**
587 String primitives for logging services.
588 */
589 BEGIN_SERVICE_DEFINITION(log_builtins_string)
590 // alloc (len+1) bytes
591 DECLARE_METHOD(void *, malloc, (size_t len));
592 // alloc (len+1) bytes, then copy len bytes from fm, and \0 terminate
593 // like my_strndup(), and unlike strndup(), \0 in input won't end copying
594 DECLARE_METHOD(char *, strndup, (const char *fm, size_t len));
595 // free allocated memory
596 DECLARE_METHOD(void, free, (void *ptr));
597
598 // length of nul terminated byte string
599 DECLARE_METHOD(size_t, length, (const char *s));
600 // find char in string, from the left
601 DECLARE_METHOD(char *, find_first, (const char *s, int c));
602 // find char in string, from the right
603 DECLARE_METHOD(char *, find_last, (const char *s, int c));
604
605 // compare two NUL-terminated byte-strings
606 DECLARE_METHOD(int, compare,
607 (const char *a, const char *b, size_t len,
608 bool case_insensitive));
609
610 /**
611 Wrapper for std::snprintf()
612 Replace all % in format string with variables from list.
613 Do not use in new code; use std::snprintf() instead.
614
615 @param to buffer to write the result to
616 @param n size of that buffer
617 @param fmt format string
618 @param ap va_list with valuables for all substitutions in format string
619
620 @retval return value of snprintf
621 */
622 DECLARE_METHOD(size_t, substitutev,
623 (char *to, size_t n, const char *fmt, va_list ap))
624 MY_ATTRIBUTE((format(printf, 3, 0)));
625
626 // replace all % in format string with variables from list (std::snprintf())
627 DECLARE_METHOD(size_t, substitute, (char *to, size_t n, const char *fmt, ...))
628 MY_ATTRIBUTE((format(printf, 3, 4)));
629
630 END_SERVICE_DEFINITION(log_builtins_string)
631
632 /**
633 Temporary primitives for logging services.
634 */
635 BEGIN_SERVICE_DEFINITION(log_builtins_tmp)
636 // Are we shutting down yet? Windows EventLog needs to know.
637 DECLARE_METHOD(bool, connection_loop_aborted, (void));
638 DECLARE_METHOD(size_t, notify_client,
639 (void *thd, uint severity, uint code, char *to, size_t n,
640 const char *format, ...))
641 MY_ATTRIBUTE((format(printf, 6, 7)));
642 END_SERVICE_DEFINITION(log_builtins_tmp)
643
644 /**
645 Syslog/Eventlog functions for logging services.
646 */
647 BEGIN_SERVICE_DEFINITION(log_builtins_syseventlog)
648 DECLARE_METHOD(int, open, (const char *name, int option, int facility));
649 DECLARE_METHOD(int, write, (enum loglevel level, const char *msg));
650 DECLARE_METHOD(int, close, (void));
651 END_SERVICE_DEFINITION(log_builtins_syseventlog)
652
653 #ifdef __cplusplus
654
655 #if !defined(LOG_H)
656
657 extern SERVICE_TYPE(log_builtins) * log_bi;
658 extern SERVICE_TYPE(log_builtins_string) * log_bs;
659
660 #define log_line_init log_bi->line_init
661 #define log_line_exit log_bi->line_exit
662 #define log_line_item_set_with_key log_bi->line_item_set_with_key
663 #define log_line_item_set log_bi->line_item_set
664 #define log_line_item_types_seen log_bi->line_item_types_seen
665 #define log_line_submit log_bi->line_submit
666 #define log_set_int log_bi->item_set_int
667 #define log_set_float log_bi->item_set_float
668 #define log_set_lexstring log_bi->item_set_lexstring
669 #define log_set_cstring log_bi->item_set_cstring
670 #define log_malloc log_bs->malloc
671 #define log_free log_bs->free
672 #define log_msg log_bs->substitutev
673 #define error_msg_by_errcode log_bi->errmsg_by_errcode
674 #define error_code_by_errsymbol log_bi->errcode_by_errsymbol
675 #else
676
677 #include "sql/derror.h"
678
679 #define log_malloc(s) my_malloc(0, (s), MYF(0))
680 #define log_free my_free
681 #define log_msg vsnprintf
682 #define error_msg_by_errcode error_message_for_error_log
683 #define error_code_by_errsymbol mysql_symbol_to_errno
684 #define log_set_int log_item_set_int
685 #define log_set_float log_item_set_float
686 #define log_set_lexstring log_item_set_lexstring
687 #define log_set_cstring log_item_set_cstring
688 #endif // LOG_H
689
690 #ifndef DISABLE_ERROR_LOGGING
691
692 #define LogErr(severity, ecode, ...) \
693 LogEvent() \
694 .prio(severity) \
695 .errcode(ecode) \
696 .subsys(LOG_SUBSYSTEM_TAG) \
697 .source_line(__LINE__) \
698 .source_file(MY_BASENAME) \
699 .function(__FUNCTION__) \
700 .lookup(ecode, ##__VA_ARGS__)
701
702 #define LogPluginErr(severity, ecode, ...) \
703 LogEvent() \
704 .prio(severity) \
705 .errcode(ecode) \
706 .subsys(LOG_SUBSYSTEM_TAG) \
707 .source_line(__LINE__) \
708 .source_file(MY_BASENAME) \
709 .function(__FUNCTION__) \
710 .lookup_quoted(ecode, "Plugin " LOG_SUBSYSTEM_TAG " reported", \
711 ##__VA_ARGS__)
712
713 #define LogPluginErrV(severity, ecode, vl) \
714 LogEvent() \
715 .prio(severity) \
716 .errcode(ecode) \
717 .subsys(LOG_SUBSYSTEM_TAG) \
718 .source_line(__LINE__) \
719 .source_file(MY_BASENAME) \
720 .function(__FUNCTION__) \
721 .lookup_quotedv(ecode, "Plugin " LOG_SUBSYSTEM_TAG " reported", vl)
722
723 #define LogPluginErrMsg(severity, ecode, ...) \
724 LogEvent() \
725 .prio(severity) \
726 .errcode(ecode) \
727 .subsys(LOG_SUBSYSTEM_TAG) \
728 .source_line(__LINE__) \
729 .source_file(MY_BASENAME) \
730 .function(__FUNCTION__) \
731 .message_quoted("Plugin " LOG_SUBSYSTEM_TAG " reported", ##__VA_ARGS__)
732
733 #else
734
dummy_log_message(longlong severity MY_ATTRIBUTE ((unused)),longlong ecode MY_ATTRIBUTE ((unused)),...)735 inline void dummy_log_message(longlong severity MY_ATTRIBUTE((unused)),
736 longlong ecode MY_ATTRIBUTE((unused)), ...) {
737 return;
738 }
739
740 #define LogErr(severity, ecode, ...) \
741 dummy_log_message(severity, ecode, ##__VA_ARGS__)
742 #define LogPluginErr(severity, ecode, ...) \
743 dummy_log_message(severity, ecode, ##__VA_ARGS__)
744 #define LogPluginErrV(severity, ecode, ...) \
745 dummy_log_message(severity, ecode, ##__VA_ARGS__)
746 #define LogPluginErrMsg(severity, ecode, ...) \
747 dummy_log_message(severity, ecode, ##__VA_ARGS__)
748
749 #endif // DISABLE_ERROR_LOGGING
750
751 /**
752 Modular logger: fluid API. Server-internal. Lets you use safe and
753 expressive syntax, like so:
754
755 LogEvent(LOG_TYPE_ERROR).prio(INFORMATION_LEVEL).message("Meow! %d", 4711);
756 */
757
758 class LogEvent {
759 private:
760 log_line *ll;
761 char *msg;
762 const char *msg_tag;
763
764 /**
765 Set MySQL error-code if none has been set yet.
766
767 @param errcode the error code (not operating system errno!)
768
769 @retval true an error occurred, value not set (OOM?)
770 @retval false value was set without incident, or did not need to be set
771 */
set_errcode(longlong errcode)772 bool set_errcode(longlong errcode) {
773 if (ll == nullptr) return true;
774
775 if (!log_line_item_types_seen(ll, LOG_ITEM_SQL_ERRCODE) &&
776 !log_line_item_types_seen(ll, LOG_ITEM_SQL_ERRSYMBOL)) {
777 return log_set_int(log_line_item_set(ll, LOG_ITEM_SQL_ERRCODE), errcode);
778 }
779 return false; // already set, that's OK then
780 }
781
782 /**
783 Set the error message.
784
785 @param fmt format string. % substitution will be performed.
786 @param ap va_list of the arguments for % substitution.
787 */
788 void set_message(const char *fmt, va_list ap)
789 MY_ATTRIBUTE((format(printf, 2, 0)));
790
791 /**
792 Set the error message (by MySQL error code).
793 The actual message will be looked up using this errcode.
794 As the message is a printf-style format string, % substitution
795 will be performed.
796
797 @param errcode MySQL error code to fetch the message string for
798 @param ap va_list of the arguments for % substitution.
799 */
800 void set_message_by_errcode(longlong errcode, va_list ap);
801
802 public:
803 /**
804 Destructor automatically sends the event on.
805 It is auto-free()d after processing.
806 */
~LogEvent()807 ~LogEvent() {
808 if (ll != nullptr) {
809 log_line_submit(this->ll);
810 log_line_exit(ll);
811 log_free(msg);
812 }
813 }
814
815 /**
816 "Full customization" constructor. Use one of the LogErr() macro
817 where possible; it's there to help you remember the minimum set
818 of particles and their data-types. Be prepared for stern looks
819 from your reviewers if you use this constructor except for external
820 (loadable) services that have no error messages registered with the
821 server, and therefore need to submit them free-form.
822 */
LogEvent()823 LogEvent() {
824 if ((ll = log_line_init()) != nullptr) {
825 if ((msg = (char *)log_malloc(LOG_BUFF_MAX)) == nullptr) {
826 log_line_exit(ll);
827 ll = nullptr;
828 }
829 } else
830 msg = nullptr;
831 msg_tag = nullptr;
832 }
833
834 /**
835
836 Set log type.
837
838 @param val the log type (LOG_TYPE_ERROR)
839
840 @retval the LogEvent, for easy fluent-style chaining.
841 */
type(enum_log_type val)842 LogEvent &type(enum_log_type val) {
843 log_set_int(log_line_item_set(this->ll, LOG_ITEM_LOG_TYPE), val);
844 return *this;
845 }
846
847 /**
848 Append a numeric error code
849
850 @param val the MySQL error code (not operating system errno!).
851
852 @retval the LogEvent, for easy fluent-style chaining.
853 */
errcode(longlong val)854 LogEvent &errcode(longlong val) {
855 log_set_int(log_line_item_set(this->ll, LOG_ITEM_SQL_ERRCODE), val);
856 return *this;
857 }
858
859 /**
860 Append a (string) error symbol
861
862 @param val error symbol. NTBS.
863
864 @retval the LogEvent, for easy fluent-style chaining.
865 */
errsymbol(const char * val)866 LogEvent &errsymbol(const char *val) {
867 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_SQL_ERRSYMBOL), val);
868 return *this;
869 }
870
871 /**
872 Append a (string) SQL state
873
874 @param val the SQLstate. NTBS.
875
876 @retval the LogEvent, for easy fluent-style chaining.
877 */
sqlstate(const char * val)878 LogEvent &sqlstate(const char *val) {
879 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_SQL_STATE), val);
880 return *this;
881 }
882
883 /**
884 Append a numeric (operating system, as opposed to MySQL) error number.
885
886 @param val the operating system errno.
887
888 @retval the LogEvent, for easy fluent-style chaining.
889 */
os_errno(longlong val)890 LogEvent &os_errno(longlong val) {
891 log_set_int(log_line_item_set(this->ll, LOG_ITEM_SYS_ERRNO), val);
892 return *this;
893 }
894
895 /**
896 Append a textual (operating system, as opposed to MySQL) error message,
897 vulgo, strerror()
898
899 @param val the error message returned by the operating system. NTBS.
900
901 @retval the LogEvent, for easy fluent-style chaining.
902 */
os_errmsg(const char * val)903 LogEvent &os_errmsg(const char *val) {
904 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_SYS_STRERROR), val);
905 return *this;
906 }
907
908 /**
909 Which source file was the problem detected in?
910
911 @param val the source file's name. NTBS.
912
913 @retval the LogEvent, for easy fluent-style chaining.
914 */
source_file(const char * val)915 LogEvent &source_file(const char *val) {
916 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_SRC_FILE), val);
917 return *this;
918 }
919
920 /**
921 Which line in the source file was the problem detected on?
922
923 @param val the line number.
924
925 @retval the LogEvent, for easy fluent-style chaining.
926 */
source_line(longlong val)927 LogEvent &source_line(longlong val) {
928 log_set_int(log_line_item_set(this->ll, LOG_ITEM_SRC_LINE), val);
929 return *this;
930 }
931
932 /**
933 Which function in the source was the problem detected in?
934
935 @param val the function's name. NTBS.
936
937 @retval the LogEvent, for easy fluent-style chaining.
938 */
function(const char * val)939 LogEvent &function(const char *val) {
940 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_SRC_FUNC), val);
941 return *this;
942 }
943
944 /**
945 Which subsystem in the source was the problem detected in?
946 ("rpl" etc.)
947
948 @param val the subsystem. NTBS.
949
950 @retval the LogEvent, for easy fluent-style chaining.
951 */
subsys(const char * val)952 LogEvent &subsys(const char *val) {
953 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_SRV_SUBSYS), val);
954 return *this;
955 }
956
957 /**
958 Which component in the source was the problem detected in?
959 This should be the same string that is given to the
960 component/service framework.
961
962 @param val the component. NTBS.
963
964 @retval the LogEvent, for easy fluent-style chaining.
965 */
component(const char * val)966 LogEvent &component(const char *val) {
967 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_SRV_COMPONENT), val);
968 return *this;
969 }
970
971 /**
972 What user were we working for at the time of the issue?
973
974 @param val the user part (of "user@host"). LEX_CSTRING.
975
976 @retval the LogEvent, for easy fluent-style chaining.
977 */
user(LEX_CSTRING val)978 LogEvent &user(LEX_CSTRING val) {
979 log_set_lexstring(log_line_item_set(this->ll, LOG_ITEM_MSC_USER), val.str,
980 val.length);
981 return *this;
982 }
983
984 /**
985 What user were we working for at the time of the issue?
986
987 @param val the user part (of "user@host"). NTBS.
988
989 @retval the LogEvent, for easy fluent-style chaining.
990 */
user(const char * val)991 LogEvent &user(const char *val) {
992 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_MSC_USER), val);
993 return *this;
994 }
995
996 /**
997 Whose session did the issue appear in?
998
999 @param val the host part (of "user@host"). LEX_CSTRING.
1000
1001 @retval the LogEvent, for easy fluent-style chaining.
1002 */
host(LEX_CSTRING val)1003 LogEvent &host(LEX_CSTRING val) {
1004 log_set_lexstring(log_line_item_set(this->ll, LOG_ITEM_MSC_HOST), val.str,
1005 val.length);
1006 return *this;
1007 }
1008
1009 /**
1010 Whose session did the issue appear in?
1011
1012 @param val the host part (of "user@host"). NTBS.
1013
1014 @retval the LogEvent, for easy fluent-style chaining.
1015 */
host(const char * val)1016 LogEvent &host(const char *val) {
1017 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_MSC_HOST), val);
1018 return *this;
1019 }
1020
1021 /**
1022 What thread / "connection ID" was the issue detected in?
1023
1024 @param val the thread_ID of the session the issue appeared in
1025
1026 @retval the LogEvent, for easy fluent-style chaining.
1027 */
thread_id(longlong val)1028 LogEvent &thread_id(longlong val) {
1029 log_set_int(log_line_item_set(this->ll, LOG_ITEM_SRV_THREAD), val);
1030 return *this;
1031 }
1032
1033 /**
1034 What query apparently caused the issue?
1035
1036 @param val the query_ID of the offending query
1037
1038 @retval the LogEvent, for easy fluent-style chaining.
1039 */
query_id(longlong val)1040 LogEvent &query_id(longlong val) {
1041 log_set_int(log_line_item_set(this->ll, LOG_ITEM_SQL_QUERY_ID), val);
1042 return *this;
1043 }
1044
1045 /**
1046 What table were we working on?
1047
1048 @param val the table's name/alias. NTBS.
1049
1050 @retval the LogEvent, for easy fluent-style chaining.
1051 */
table_name(const char * val)1052 LogEvent &table_name(const char *val) {
1053 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_SQL_TABLE_NAME), val);
1054 return *this;
1055 }
1056
1057 /**
1058 Set error message priority.
1059 Assign one of ERROR_LEVEL, WARNING_LEVEL, INFORMATION_LEVEL.
1060 log-writers and other sinks should use this value (rather
1061 than that of LOG_ITEM_LOG_EPRIO):
1062
1063 - file writers should use the value to determine
1064 what label to write (perhaps by submitting it to label_from_prio())
1065
1066 - sinks that submit the event data to a sub-system outside of
1067 the MySQL server (such as syslog, EventLog, systemd journal, etc.)
1068 should translate this value into a priority/log level understood
1069 by that target subsystem.
1070
1071 @param val The priority for this LogEvent.
1072
1073 @retval the LogEvent, for easy fluent-style chaining.
1074 */
prio(longlong val)1075 LogEvent &prio(longlong val) {
1076 log_set_int(log_line_item_set(this->ll, LOG_ITEM_LOG_PRIO), val);
1077 return *this;
1078 }
1079
1080 /**
1081 Set a label (usually "warning"/"error"/"information").
1082 Will be derived from prio if not set explicitly.
1083 Some log services may ignore custom labels.
1084
1085 @param val the (custom) label to set
1086
1087 @retval the LogEvent, for easy fluent-style chaining.
1088 */
label(const char * val)1089 LogEvent &label(const char *val) {
1090 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_LOG_LABEL), val);
1091 return *this;
1092 }
1093
1094 /**
1095 Add a message to the event, verbatim (i.e. with no % substitutions).
1096 This is an analog of message("%s", message); it can be used when
1097 message may contain user input or a message from another subsystem
1098 that could contain % that must not be interpreted as an invitation
1099 to do % substitutions.
1100
1101 If you use this in a context other than an external service that
1102 has no messages registered with the server, your reviewers will
1103 say unkind things about you. Use registered messages and their
1104 error codes wherever possible!
1105
1106 @param msg_arg the message. % substitution will not happen.
1107
1108 @retval the LogEvent, for easy fluent-style chaining.
1109 */
verbatim(const char * msg_arg)1110 LogEvent &verbatim(const char *msg_arg) {
1111 log_set_cstring(log_line_item_set(this->ll, LOG_ITEM_LOG_MESSAGE), msg_arg);
1112 return *this;
1113 }
1114
1115 /**
1116 Fill in a format string by substituting the % with the given
1117 arguments, then add the result as the event's message.
1118
1119 If you use this in a context other than an external service that
1120 has no messages registered with the server, your reviewers will
1121 say unkind things about you. Use registered messages and their
1122 error codes wherever possible!
1123
1124 @param fmt message (treated as a printf-style format-string,
1125 so % substitution will happen)
1126 @param ... varargs to satisfy any % in the message
1127
1128 @retval the LogEvent, for easy fluent-style chaining.
1129 */
1130 LogEvent &message(const char *fmt, ...) MY_ATTRIBUTE((format(printf, 2, 3)));
1131
1132 /**
1133 Fill in a format string by substituting the % with the given
1134 arguments and tag, then add the result as the event's message.
1135
1136 @param tag Tag to prefix to message.
1137 @param fmt message (treated as a printf-style format-string,
1138 so % substitution will happen)
1139 @param ... varargs to satisfy any % in the message
1140
1141 @retval the LogEvent, for easy fluent-style chaining.
1142 */
message_quoted(const char * tag,const char * fmt,...)1143 LogEvent &message_quoted(const char *tag, const char *fmt, ...)
1144 MY_ATTRIBUTE((format(printf, 3, 4))) {
1145 msg_tag = tag;
1146
1147 va_list args;
1148 va_start(args, fmt);
1149 set_message(fmt, args);
1150 va_end(args);
1151
1152 return *this;
1153 }
1154
1155 /**
1156 Find an error message by its MySQL error code.
1157 Substitute the % in that message with the given
1158 arguments, then add the result as the event's message.
1159
1160 @param errcode MySQL error code for the message in question,
1161 e.g. ER_STARTUP
1162 @param ... varargs to satisfy any % in the message
1163
1164 @retval the LogEvent, for easy fluent-style chaining.
1165 */
lookup(longlong errcode,...)1166 LogEvent &lookup(longlong errcode, ...) {
1167 va_list args;
1168 va_start(args, errcode);
1169 set_message_by_errcode(errcode, args);
1170 va_end(args);
1171
1172 return *this;
1173 }
1174
lookup_quoted(longlong errcode,const char * tag,...)1175 LogEvent &lookup_quoted(longlong errcode, const char *tag, ...) {
1176 msg_tag = tag;
1177
1178 va_list args;
1179 va_start(args, tag);
1180 set_message_by_errcode(errcode, args);
1181 va_end(args);
1182
1183 return *this;
1184 }
1185
lookup_quotedv(longlong errcode,const char * tag,va_list vl)1186 LogEvent &lookup_quotedv(longlong errcode, const char *tag, va_list vl) {
1187 msg_tag = tag;
1188 set_message_by_errcode(errcode, vl);
1189
1190 return *this;
1191 }
1192
1193 /**
1194 Add a ad hoc integer value with the given key.
1195
1196 @param key user-defined key (i.e. not wellknown). NTBS.
1197 @param val value.
1198
1199 @retval the LogEvent, for easy fluent-style chaining.
1200 */
int_value(const char * key,longlong val)1201 LogEvent &int_value(const char *key, longlong val) {
1202 log_set_int(log_line_item_set_with_key(this->ll, LOG_ITEM_GEN_INTEGER, key,
1203 LOG_ITEM_FREE_NONE),
1204 val);
1205 return *this;
1206 }
1207
1208 /**
1209 Add a ad hoc (not "well-known") float value with the given key.
1210
1211 @param key user-defined key (i.e. not wellknown). NTBS.
1212 @param val value.
1213
1214 @retval the LogEvent, for easy fluent-style chaining.
1215 */
float_value(const char * key,double val)1216 LogEvent &float_value(const char *key, double val) {
1217 log_set_float(log_line_item_set_with_key(this->ll, LOG_ITEM_GEN_FLOAT, key,
1218 LOG_ITEM_FREE_NONE),
1219 val);
1220 return *this;
1221 }
1222
1223 /**
1224 Add a ad hoc string value with the given key.
1225
1226 @param key user-defined key (i.e. not wellknown). NTBS.
1227 @param val value.
1228 @param len length in bytes of the value.
1229
1230 @retval the LogEvent, for easy fluent-style chaining.
1231 */
string_value(const char * key,const char * val,size_t len)1232 LogEvent &string_value(const char *key, const char *val, size_t len) {
1233 log_set_lexstring(
1234 log_line_item_set_with_key(this->ll, LOG_ITEM_GEN_LEX_STRING, key,
1235 LOG_ITEM_FREE_NONE),
1236 val, len);
1237 return *this;
1238 }
1239
1240 /**
1241 Add a ad hoc string value with the given key.
1242
1243 @param key user-defined key (i.e. not wellknown). NTBS.
1244 @param val value. NTBS.
1245
1246 @retval the LogEvent, for easy fluent-style chaining.
1247 */
string_value(const char * key,const char * val)1248 LogEvent &string_value(const char *key, const char *val) {
1249 log_set_cstring(
1250 log_line_item_set_with_key(this->ll, LOG_ITEM_GEN_LEX_STRING, key,
1251 LOG_ITEM_FREE_NONE),
1252 val);
1253 return *this;
1254 }
1255 };
1256
set_message_by_errcode(longlong errcode,va_list ap)1257 inline void LogEvent::set_message_by_errcode(longlong errcode, va_list ap) {
1258 const char *fmt = error_msg_by_errcode((int)errcode);
1259
1260 if ((fmt == nullptr) || (*fmt == '\0')) fmt = "invalid error code";
1261
1262 set_errcode(errcode);
1263 set_message(fmt, ap);
1264 }
1265
set_message(const char * fmt,va_list ap)1266 inline void LogEvent::set_message(const char *fmt, va_list ap) {
1267 if ((ll != nullptr) && (msg != nullptr)) {
1268 char buf[LOG_BUFF_MAX];
1269 if (msg_tag != nullptr) {
1270 snprintf(buf, LOG_BUFF_MAX - 1, "%s: \'%s\'", msg_tag, fmt);
1271 fmt = buf;
1272 }
1273 size_t len = log_msg(msg, LOG_BUFF_MAX - 1, fmt, ap);
1274 log_set_lexstring(log_line_item_set(this->ll, LOG_ITEM_LOG_MESSAGE), msg,
1275 len);
1276 }
1277 }
1278
message(const char * fmt,...)1279 inline LogEvent &LogEvent::message(const char *fmt, ...) {
1280 va_list args;
1281 va_start(args, fmt);
1282 set_message(fmt, args);
1283 va_end(args);
1284
1285 return *this;
1286 }
1287
1288 // Methods initialize and de-initialize logging service for plugins.
1289 #if defined(MYSQL_DYNAMIC_PLUGIN)
1290
1291 /**
1292 Method to de-initialize logging service in plugin.
1293
1294 param[in,out] reg_srv Plugin registry service.
1295 param[in,out] log_bi Error logging service.
1296 param[in,out] log_bs String service for error logging.
1297 */
deinit_logging_service_for_plugin(SERVICE_TYPE (registry)** reg_srv,SERVICE_TYPE (log_builtins)** log_bi,SERVICE_TYPE (log_builtins_string)** log_bs)1298 inline void deinit_logging_service_for_plugin(
1299 SERVICE_TYPE(registry) * *reg_srv, SERVICE_TYPE(log_builtins) * *log_bi,
1300 SERVICE_TYPE(log_builtins_string) * *log_bs) {
1301 if (*log_bi) (*reg_srv)->release((my_h_service)(*log_bi));
1302 if (*log_bs) (*reg_srv)->release((my_h_service)(*log_bs));
1303 mysql_plugin_registry_release(*reg_srv);
1304 *log_bi = nullptr;
1305 *log_bs = nullptr;
1306 *reg_srv = nullptr;
1307 }
1308
1309 /**
1310 Method to de-initialize logging service in plugin.
1311
1312 param[in,out] reg_srv Plugin registry service.
1313 param[in,out] log_bi Error logging service.
1314 param[in,out] log_bs String service for error logging.
1315
1316 @retval false Success.
1317 @retval true Failed.
1318 */
init_logging_service_for_plugin(SERVICE_TYPE (registry)** reg_srv,SERVICE_TYPE (log_builtins)** log_bi,SERVICE_TYPE (log_builtins_string)** log_bs)1319 inline bool init_logging_service_for_plugin(
1320 SERVICE_TYPE(registry) * *reg_srv, SERVICE_TYPE(log_builtins) * *log_bi,
1321 SERVICE_TYPE(log_builtins_string) * *log_bs) {
1322 my_h_service log_srv = nullptr;
1323 my_h_service log_str_srv = nullptr;
1324 *reg_srv = mysql_plugin_registry_acquire();
1325 if (!(*reg_srv)->acquire("log_builtins.mysql_server", &log_srv) &&
1326 !(*reg_srv)->acquire("log_builtins_string.mysql_server", &log_str_srv)) {
1327 (*log_bi) = reinterpret_cast<SERVICE_TYPE(log_builtins) *>(log_srv);
1328 (*log_bs) =
1329 reinterpret_cast<SERVICE_TYPE(log_builtins_string) *>(log_str_srv);
1330 } else {
1331 deinit_logging_service_for_plugin(reg_srv, log_bi, log_bs);
1332 return true;
1333 }
1334 return false;
1335 }
1336
1337 #elif defined(EXTRA_CODE_FOR_UNIT_TESTING)
1338
1339 /**
1340 Method is used by unit tests.
1341
1342 param[in,out] reg_srv Plugin registry service.
1343 param[in,out] log_bi Error logging service.
1344 param[in,out] log_bs String service for error logging.
1345
1346 @retval false Success.
1347 @retval true Failed.
1348 */
init_logging_service_for_plugin(SERVICE_TYPE (registry)** reg_srv MY_ATTRIBUTE ((unused)),SERVICE_TYPE (log_builtins)** log_bi MY_ATTRIBUTE ((unused)),SERVICE_TYPE (log_builtins_string)** log_bs MY_ATTRIBUTE ((unused)))1349 inline bool init_logging_service_for_plugin(
1350 SERVICE_TYPE(registry) * *reg_srv MY_ATTRIBUTE((unused)),
1351 SERVICE_TYPE(log_builtins) * *log_bi MY_ATTRIBUTE((unused)),
1352 SERVICE_TYPE(log_builtins_string) * *log_bs MY_ATTRIBUTE((unused)))
1353
1354 {
1355 return false;
1356 }
1357
1358 /**
1359 Method is used by unit tests.
1360
1361 param[in,out] reg_srv Plugin registry service.
1362 param[in,out] log_bi Error logging service.
1363 param[in,out] log_bs String service for error logging.
1364 */
deinit_logging_service_for_plugin(SERVICE_TYPE (registry)** reg_srv MY_ATTRIBUTE ((unused)),SERVICE_TYPE (log_builtins)** log_bi MY_ATTRIBUTE ((unused)),SERVICE_TYPE (log_builtins_string)** log_bs MY_ATTRIBUTE ((unused)))1365 inline void deinit_logging_service_for_plugin(
1366 SERVICE_TYPE(registry) * *reg_srv MY_ATTRIBUTE((unused)),
1367 SERVICE_TYPE(log_builtins) * *log_bi MY_ATTRIBUTE((unused)),
1368 SERVICE_TYPE(log_builtins_string) * *log_bs MY_ATTRIBUTE((unused))) {}
1369
1370 #endif // MYSQL_DYNAMIC_PLUGIN
1371
1372 #endif // __cplusplus
1373
1374 #endif
1375