1 /* Copyright (c) 2005, 2019, 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,
5    as 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 additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef LOG_H
24 #define LOG_H
25 
26 #include "unireg.h"                    // REQUIRED: for other includes
27 #include "handler.h"                            /* my_xid */
28 
29 /**
30   the struct aggregates two paramenters that identify an event
31   uniquely in scope of communication of a particular master and slave couple.
32   I.e there can not be 2 events from the same staying connected master which
33   have the same coordinates.
34   @note
35   Such identifier is not yet unique generally as the event originating master
36   is resetable. Also the crashed master can be replaced with some other.
37 */
38 typedef struct event_coordinates
39 {
40   char * file_name; // binlog file name (directories stripped)
41   my_off_t  pos;       // event's position in the binlog file
42 } LOG_POS_COORD;
43 
44 /**
45   Transaction Coordinator Log.
46 
47   A base abstract class for three different implementations of the
48   transaction coordinator.
49 
50   The server uses the transaction coordinator to order transactions
51   correctly and there are three different implementations: one using
52   an in-memory structure, one dummy that does not do anything, and one
53   using the binary log for transaction coordination.
54 */
55 class TC_LOG
56 {
57   public:
58   int using_heuristic_recover();
TC_LOG()59   TC_LOG() {}
~TC_LOG()60   virtual ~TC_LOG() {}
61 
62   enum enum_result {
63     RESULT_SUCCESS,
64     RESULT_ABORTED,
65     RESULT_INCONSISTENT
66   };
67 
68   virtual int open(const char *opt_name)=0;
69   virtual void close()=0;
70 
71   /**
72      Log a commit record of the transaction to the transaction
73      coordinator log.
74 
75      When the function returns, the transaction commit is properly
76      logged to the transaction coordinator log and can be committed in
77      the storage engines.
78 
79      @param thd Session to log transaction for.
80      @param all @c True if this is a "real" commit, @c false if it is a "statement" commit.
81 
82      @return Error code on failure, zero on success.
83    */
84   virtual enum_result commit(THD *thd, bool all) = 0;
85 
86   /**
87      Log a rollback record of the transaction to the transaction
88      coordinator log.
89 
90      When the function returns, the transaction have been aborted in
91      the transaction coordinator log.
92 
93      @param thd Session to log transaction record for.
94 
95      @param all @c true if an explicit commit or an implicit commit
96      for a statement, @c false if an internal commit of the statement.
97 
98      @return Error code on failure, zero on success.
99    */
100   virtual int rollback(THD *thd, bool all) = 0;
101   /**
102      Log a prepare record of the transaction to the storage engines.
103 
104      @param thd Session to log transaction record for.
105 
106      @param all @c true if an explicit commit or an implicit commit
107      for a statement, @c false if an internal commit of the statement.
108 
109      @return Error code on failure, zero on success.
110    */
111   virtual int prepare(THD *thd, bool all) = 0;
112 
113   /**
114      Acquire an exclusive lock to block binary log updates and commits. This is
115      used by START TRANSACTION WITH CONSISTENT SNAPSHOT to create an atomic
116      snapshot.
117   */
118   virtual void xlock(void) = 0;
119 
120   /** Release lock acquired with xlock(). */
121   virtual void xunlock(void) = 0;
122 
123   /**
124      Acquire a shared lock to block commits. This is used when calling
125      ha_commit_low() to block commits if there's an exclusive lock acquired by
126      START TRANSACTION WITH CONSISTENT SNAPSHOT.
127   */
128   virtual void slock(void) = 0;
129 
130   /** Release lock acquired with slock(). */
131   virtual void sunlock(void) = 0;
132 };
133 
134 
135 class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging
136 {
137 public:
TC_LOG_DUMMY()138   TC_LOG_DUMMY() {}
open(const char * opt_name)139   int open(const char *opt_name)        { return 0; }
close()140   void close()                          { }
commit(THD * thd,bool all)141   enum_result commit(THD *thd, bool all) {
142     return ha_commit_low(thd, all) ? RESULT_ABORTED : RESULT_SUCCESS;
143   }
rollback(THD * thd,bool all)144   int rollback(THD *thd, bool all) {
145     return ha_rollback_low(thd, all);
146   }
prepare(THD * thd,bool all)147   int prepare(THD *thd, bool all) {
148     return ha_prepare_low(thd, all);
149   }
xlock(void)150   void xlock(void) {}
xunlock(void)151   void xunlock(void) {}
slock(void)152   void slock(void) {}
sunlock(void)153   void sunlock(void) {}
154 };
155 
156 #ifdef HAVE_MMAP
157 class TC_LOG_MMAP: public TC_LOG
158 {
159   public:                // only to keep Sun Forte on sol9x86 happy
160   typedef enum {
161     PS_POOL,                 // page is in pool
162     PS_ERROR,                // last sync failed
163     PS_DIRTY                 // new xids added since last sync
164   } PAGE_STATE;
165 
166   private:
167   typedef struct st_page {
168     struct st_page *next; // page a linked in a fifo queue
169     my_xid *start, *end;  // usable area of a page
170     my_xid *ptr;          // next xid will be written here
171     int size, free;       // max and current number of free xid slots on the page
172     int waiters;          // number of waiters on condition
173     PAGE_STATE state;     // see above
174     mysql_mutex_t lock; // to access page data or control structure
175     mysql_cond_t  cond; // to wait for a sync
176   } PAGE;
177 
178   char logname[FN_REFLEN];
179   File fd;
180   my_off_t file_length;
181   uint npages, inited;
182   uchar *data;
183   struct st_page *pages, *syncing, *active, *pool, **pool_last_ptr;
184   /*
185     note that, e.g. LOCK_active is only used to protect
186     'active' pointer, to protect the content of the active page
187     one has to use active->lock.
188     Same for LOCK_pool and LOCK_sync
189   */
190   mysql_mutex_t LOCK_active, LOCK_pool, LOCK_sync;
191   mysql_cond_t COND_pool, COND_active;
192 
193   public:
TC_LOG_MMAP()194   TC_LOG_MMAP(): inited(0) {}
195   int open(const char *opt_name);
196   void close();
197   enum_result commit(THD *thd, bool all);
rollback(THD * thd,bool all)198   int rollback(THD *thd, bool all)      { return ha_rollback_low(thd, all); }
prepare(THD * thd,bool all)199   int prepare(THD *thd, bool all)       { return ha_prepare_low(thd, all); }
xlock(void)200   void xlock(void) { mysql_rwlock_wrlock(&LOCK_consistent_snapshot); }
xunlock(void)201   void xunlock(void) { mysql_rwlock_unlock(&LOCK_consistent_snapshot); }
slock(void)202   void slock(void) { mysql_rwlock_rdlock(&LOCK_consistent_snapshot); }
sunlock(void)203   void sunlock(void) { mysql_rwlock_unlock(&LOCK_consistent_snapshot); }
204   int recover();
205   uint size() const;
206 
207 private:
208   int log_xid(THD *thd, my_xid xid);
209   int unlog(ulong cookie, my_xid xid);
210   void get_active_from_pool();
211   int sync();
212   int overflow();
213 
214   friend class TCLogMMapTest;
215 };
216 #else
217 #define TC_LOG_MMAP TC_LOG_DUMMY
218 #endif
219 
220 extern TC_LOG *tc_log;
221 extern TC_LOG_MMAP tc_log_mmap;
222 extern TC_LOG_DUMMY tc_log_dummy;
223 
224 /* log info errors */
225 #define LOG_INFO_EOF -1
226 #define LOG_INFO_IO  -2
227 #define LOG_INFO_INVALID -3
228 #define LOG_INFO_SEEK -4
229 #define LOG_INFO_MEM -6
230 #define LOG_INFO_FATAL -7
231 #define LOG_INFO_IN_USE -8
232 #define LOG_INFO_EMFILE -9
233 
234 
235 /* bitmap to SQL_LOG::close() */
236 #define LOG_CLOSE_INDEX		1
237 #define LOG_CLOSE_TO_BE_OPENED	2
238 #define LOG_CLOSE_STOP_EVENT	4
239 
240 /*
241   Maximum unique log filename extension.
242   Note: setting to 0x7FFFFFFF due to atol windows
243         overflow/truncate.
244  */
245 #define MAX_LOG_UNIQUE_FN_EXT 0x7FFFFFFF
246 
247 /*
248    Number of warnings that will be printed to error log
249    before extension number is exhausted.
250 */
251 #define LOG_WARN_UNIQUE_FN_EXT_LEFT 1000
252 
253 /* max size of log messages (error log, plugins' logging, general log) */
254 #define MAX_LOG_BUFFER_SIZE 1024
255 #define MAX_TIME_SIZE 32
256 
257 #ifdef HAVE_PSI_INTERFACE
258 extern PSI_mutex_key key_LOG_INFO_lock;
259 #endif
260 
261 /*
262   Note that we destroy the lock mutex in the desctructor here.
263   This means that object instances cannot be destroyed/go out of scope,
264   until we have reset thd->current_linfo to NULL;
265  */
266 typedef struct st_log_info
267 {
268   char log_file_name[FN_REFLEN];
269   my_off_t index_file_offset, index_file_start_offset;
270   my_off_t pos;
271   bool fatal; // if the purge happens to give us a negative offset
272   int entry_index; //used in purge_logs(), calculatd in find_log_pos().
273   mysql_mutex_t lock;
st_log_infost_log_info274   st_log_info()
275     : index_file_offset(0), index_file_start_offset(0),
276       pos(0), fatal(0), entry_index(0)
277     {
278       log_file_name[0] = '\0';
279       mysql_mutex_init(key_LOG_INFO_lock, &lock, MY_MUTEX_INIT_FAST);
280     }
~st_log_infost_log_info281   ~st_log_info() { mysql_mutex_destroy(&lock);}
282 } LOG_INFO;
283 
284 /*
285   Currently we have only 3 kinds of logging functions: old-fashioned
286   logs, stdout and csv logging routines.
287 */
288 #define MAX_LOG_HANDLERS_NUM 3
289 
290 /* log event handler flags */
291 #define LOG_NONE       1
292 #define LOG_FILE       2
293 #define LOG_TABLE      4
294 
295 enum enum_log_type { LOG_UNKNOWN, LOG_NORMAL, LOG_BIN };
296 enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED };
297 
298 /*
299   TODO use mmap instead of IO_CACHE for binlog
300   (mmap+fsync is two times faster than write+fsync)
301 */
302 
303 class MYSQL_LOG
304 {
305 public:
306   MYSQL_LOG();
307   void init_pthread_objects();
308   void cleanup();
309   bool open(
310 #ifdef HAVE_PSI_INTERFACE
311             PSI_file_key log_file_key,
312 #endif
313             const char *log_name,
314             enum_log_type log_type,
315             const char *new_name,
316             enum cache_type io_cache_type_arg);
317   bool init_and_set_log_file_name(const char *log_name,
318                                   const char *new_name,
319                                   enum_log_type log_type_arg,
320                                   enum cache_type io_cache_type_arg);
321   void init(enum_log_type log_type_arg,
322             enum cache_type io_cache_type_arg);
323   void close(uint exiting);
is_open()324   inline bool is_open() { return log_state != LOG_CLOSED; }
325   const char *generate_name(const char *log_name, const char *suffix,
326                             bool strip_ext, char *buff);
327   int generate_new_name(char *new_name, const char *log_name);
328  protected:
329   /* LOCK_log is inited by init_pthread_objects() */
330   mysql_mutex_t LOCK_log;
331   char *name;
332   char log_file_name[FN_REFLEN];
333   char time_buff[20], db[NAME_LEN + 1];
334   bool write_error, inited;
335   IO_CACHE log_file;
336   enum_log_type log_type;
337   volatile enum_log_state log_state;
338   enum cache_type io_cache_type;
339   friend class Log_event;
340   ulong cur_log_ext;
341 #ifdef HAVE_PSI_INTERFACE
342   /** Instrumentation key to use for file io in @c log_file */
343   PSI_file_key m_log_file_key;
344   /** The instrumentation key to use for @ LOCK_log. */
345   PSI_mutex_key m_key_LOCK_log;
346 #endif
347   int purge_up_to(ulong to_ext, const char *log_name);
348 };
349 
350 
351 enum enum_general_log_table_field
352 {
353   GLT_FIELD_EVENT_TIME = 0,
354   GLT_FIELD_USER_HOST,
355   GLT_FIELD_THREAD_ID,
356   GLT_FIELD_SERVER_ID,
357   GLT_FIELD_COMMAND_TYPE,
358   GLT_FIELD_ARGUMENT,
359   GLT_FIELD_COUNT
360 };
361 
362 
363 enum enum_slow_query_log_table_field
364 {
365   SQLT_FIELD_START_TIME = 0,
366   SQLT_FIELD_USER_HOST,
367   SQLT_FIELD_QUERY_TIME,
368   SQLT_FIELD_LOCK_TIME,
369   SQLT_FIELD_ROWS_SENT,
370   SQLT_FIELD_ROWS_EXAMINED,
371   SQLT_FIELD_DATABASE,
372   SQLT_FIELD_LAST_INSERT_ID,
373   SQLT_FIELD_INSERT_ID,
374   SQLT_FIELD_SERVER_ID,
375   SQLT_FIELD_SQL_TEXT,
376   SQLT_FIELD_THREAD_ID,
377   SQLT_FIELD_COUNT
378 };
379 
380 
381 class MYSQL_QUERY_LOG: public MYSQL_LOG
382 {
383 public:
MYSQL_QUERY_LOG()384   MYSQL_QUERY_LOG() : last_time(0) {}
385   bool reopen_file();
386   bool write(time_t event_time, const char *user_host,
387              uint user_host_len, my_thread_id thread_id,
388              const char *command_type, uint command_type_len,
389              const char *sql_text, uint sql_text_len);
390   bool write(THD *thd, ulonglong current_time, time_t query_start_arg,
391              const char *user_host, uint user_host_len,
392              ulonglong query_utime, ulonglong lock_utime, bool is_command,
393              const char *sql_text, uint sql_text_len);
open_slow_log(const char * log_name)394   bool open_slow_log(const char *log_name)
395   {
396     char buf[FN_REFLEN];
397     return open(
398 #ifdef HAVE_PSI_INTERFACE
399                 key_file_slow_log,
400 #endif
401                 generate_name(log_name, "-slow.log", 0, buf),
402                 LOG_NORMAL, 0, WRITE_CACHE);
403   }
open_query_log(const char * log_name)404   bool open_query_log(const char *log_name)
405   {
406     char buf[FN_REFLEN];
407     return open(
408 #ifdef HAVE_PSI_INTERFACE
409                 key_file_query_log,
410 #endif
411                 generate_name(log_name, ".log", 0, buf),
412                 LOG_NORMAL, 0, WRITE_CACHE);
413   }
414   int rotate(ulong max_size, bool *need_purge);
415   int new_file();
416 
417 private:
418   time_t last_time;
419 };
420 
421 class Log_event_handler
422 {
423 public:
Log_event_handler()424   Log_event_handler() {}
425   virtual bool init()= 0;
426   virtual void cleanup()= 0;
427 
428   virtual bool log_slow(THD *thd, ulonglong current_time,
429                         time_t query_start_arg, const char *user_host,
430                         uint user_host_len, ulonglong query_utime,
431                         ulonglong lock_utime, bool is_command,
432                         const char *sql_text, uint sql_text_len)= 0;
433   virtual bool log_error(enum loglevel level, const char *format,
434                          va_list args)= 0;
435   virtual bool log_general(THD *thd, time_t event_time, const char *user_host,
436                            uint user_host_len, my_thread_id thread_id,
437                            const char *command_type, uint command_type_len,
438                            const char *sql_text, uint sql_text_len,
439                            const CHARSET_INFO *client_cs)= 0;
~Log_event_handler()440   virtual ~Log_event_handler() {}
441 };
442 
443 
444 int check_if_log_table(size_t db_len, const char *db, size_t table_name_len,
445                        const char *table_name, bool check_if_opened);
446 
447 class Log_to_csv_event_handler: public Log_event_handler
448 {
449 public:
450   Log_to_csv_event_handler();
451   ~Log_to_csv_event_handler();
452   virtual bool init();
453   virtual void cleanup();
454 
455   virtual bool log_slow(THD *thd, ulonglong current_utime,
456                         time_t query_start_arg, const char *user_host,
457                         uint user_host_len, ulonglong query_utime,
458                         ulonglong lock_utime, bool is_command,
459                         const char *sql_text, uint sql_text_len);
460   virtual bool log_error(enum loglevel level, const char *format,
461                          va_list args);
462   virtual bool log_general(THD *thd, time_t event_time, const char *user_host,
463                            uint user_host_len, my_thread_id thread_id,
464                            const char *command_type, uint command_type_len,
465                            const char *sql_text, uint sql_text_len,
466                            const CHARSET_INFO *client_cs);
467 
468   int activate_log(THD *thd, uint log_type);
469 };
470 
471 
472 /* type of the log table */
473 #define QUERY_LOG_SLOW 1
474 #define QUERY_LOG_GENERAL 2
475 
476 class Log_to_file_event_handler: public Log_event_handler
477 {
478   MYSQL_QUERY_LOG mysql_log;
479   MYSQL_QUERY_LOG mysql_slow_log;
480   bool is_initialized;
481 public:
Log_to_file_event_handler()482   Log_to_file_event_handler(): is_initialized(FALSE)
483   {}
484   virtual bool init();
485   virtual void cleanup();
486 
487   virtual bool log_slow(THD *thd, ulonglong current_utime,
488                         time_t query_start_arg, const char *user_host,
489                         uint user_host_len, ulonglong query_utime,
490                         ulonglong lock_utime, bool is_command,
491                         const char *sql_text, uint sql_text_len);
492   virtual bool log_error(enum loglevel level, const char *format,
493                          va_list args);
494   virtual bool log_general(THD *thd, time_t event_time, const char *user_host,
495                            uint user_host_len, my_thread_id thread_id,
496                            const char *command_type, uint command_type_len,
497                            const char *sql_text, uint sql_text_len,
498                            const CHARSET_INFO *client_cs);
499   void flush();
500   void flush_slow_log();
501   void init_pthread_objects();
get_mysql_slow_log()502   MYSQL_QUERY_LOG *get_mysql_slow_log() { return &mysql_slow_log; }
get_mysql_log()503   MYSQL_QUERY_LOG *get_mysql_log() { return &mysql_log; }
504 };
505 
506 
507 /* Class which manages slow, general and error log event handlers */
508 class LOGGER
509 {
510   mysql_rwlock_t LOCK_logger;
511   /* flag to check whether logger mutex is initialized */
512   uint inited;
513 
514   /* available log handlers */
515   Log_to_csv_event_handler *table_log_handler;
516   Log_to_file_event_handler *file_log_handler;
517 
518   /* NULL-terminated arrays of log handlers */
519   Log_event_handler *error_log_handler_list[MAX_LOG_HANDLERS_NUM + 1];
520   Log_event_handler *slow_log_handler_list[MAX_LOG_HANDLERS_NUM + 1];
521   Log_event_handler *general_log_handler_list[MAX_LOG_HANDLERS_NUM + 1];
522 
523 public:
524 
525   bool is_log_tables_initialized;
526 
LOGGER()527   LOGGER() : inited(0), table_log_handler(NULL),
528              file_log_handler(NULL), is_log_tables_initialized(FALSE)
529   {}
lock_shared()530   void lock_shared() { mysql_rwlock_rdlock(&LOCK_logger); }
lock_exclusive()531   void lock_exclusive() { mysql_rwlock_wrlock(&LOCK_logger); }
unlock()532   void unlock() { mysql_rwlock_unlock(&LOCK_logger); }
533   bool is_log_table_enabled(uint log_table_type);
534   bool log_command(THD *thd, enum enum_server_command command,
535                    const char *query_str, size_t query_length);
536 
537   /*
538     We want to initialize all log mutexes as soon as possible,
539     but we cannot do it in constructor, as safe_mutex relies on
540     initialization, performed by MY_INIT(). This why this is done in
541     this function.
542   */
543   void init_base();
544   void init_log_tables();
545   bool flush_logs(THD *thd);
546   bool flush_slow_log();
547   bool flush_general_log();
548   /* Perform basic logger cleanup. this will leave e.g. error log open. */
549   void cleanup_base();
550   /* Free memory. Nothing could be logged after this function is called */
551   void cleanup_end();
552   bool error_log_print(enum loglevel level, const char *format,
553                       va_list args);
554   bool slow_log_print(THD *thd, const char *query, uint query_length);
555   bool general_log_print(THD *thd,enum enum_server_command command,
556                          const char *format, va_list args);
557   bool general_log_write(THD *thd, enum enum_server_command command,
558                          const char *query, uint query_length);
559 
560   /* we use this function to setup all enabled log event handlers */
561   int set_handlers(uint error_log_printer,
562                    uint slow_log_printer,
563                    uint general_log_printer);
564   void init_error_log(uint error_log_printer);
565   void init_slow_log(uint slow_log_printer);
566   void init_general_log(uint general_log_printer);
567   void deactivate_log_handler(THD* thd, uint log_type);
568   bool activate_log_handler(THD* thd, uint log_type);
get_slow_log_file_handler()569   MYSQL_QUERY_LOG *get_slow_log_file_handler() const
570   {
571     if (file_log_handler)
572       return file_log_handler->get_mysql_slow_log();
573     return NULL;
574   }
get_log_file_handler()575   MYSQL_QUERY_LOG *get_log_file_handler() const
576   {
577     if (file_log_handler)
578       return file_log_handler->get_mysql_log();
579     return NULL;
580   }
581 };
582 
583 enum enum_binlog_row_image {
584   /** PKE in the before image and changed columns in the after image */
585   BINLOG_ROW_IMAGE_MINIMAL= 0,
586   /** Whenever possible, before and after image contain all columns except blobs. */
587   BINLOG_ROW_IMAGE_NOBLOB= 1,
588   /** All columns in both before and after image. */
589   BINLOG_ROW_IMAGE_FULL= 2
590 };
591 
592 enum enum_binlog_format {
593   BINLOG_FORMAT_MIXED= 0, ///< statement if safe, otherwise row - autodetected
594   BINLOG_FORMAT_STMT=  1, ///< statement-based
595   BINLOG_FORMAT_ROW=   2, ///< row-based
596   BINLOG_FORMAT_UNSPEC=3  ///< thd_binlog_format() returns it when binlog is closed
597 };
598 
599 void exec_binlog_error_action_abort(const char* err_string);
600 int query_error_code(THD *thd, bool not_killed);
601 uint purge_log_get_error_code(int res);
602 
603 int vprint_msg_to_log(enum loglevel level, const char *format, va_list args);
604 void sql_print_error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
605 void sql_print_warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
606 void sql_print_information(const char *format, ...)
607   ATTRIBUTE_FORMAT(printf, 1, 2);
608 typedef void (*sql_print_message_func)(const char *format, ...)
609   ATTRIBUTE_FORMAT_FPTR(printf, 1, 2);
610 extern sql_print_message_func sql_print_message_handlers[];
611 
612 int error_log_print(enum loglevel level, const char *format,
613                     va_list args);
614 
615 bool slow_log_print(THD *thd, const char *query, uint query_length);
616 
617 bool general_log_print(THD *thd, enum enum_server_command command,
618                        const char *format,...);
619 
620 bool general_log_write(THD *thd, enum enum_server_command command,
621                        const char *query, uint query_length);
622 
623 void sql_perror(const char *message);
624 bool flush_error_log();
625 
626 char *make_log_name(char *buff, const char *name, const char* log_ext);
627 
628 /**
629   Check given log name against certain blacklisted names/extensions.
630 
631   @param name     Log name to check
632   @param len      Length of log name
633 
634   @returns true if name is valid, false otherwise.
635 */
636 bool is_valid_log_name(const char *name, size_t len);
637 
638 extern LOGGER logger;
639 
640 #endif /* LOG_H */
641