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