1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup logger Logging functions
36 * @ingroup dnscore
37 * @brief
38 *
39 *
40 *
41 * @{
42 *
43 *----------------------------------------------------------------------------*/
44
45 #include "dnscore/dnscore-config.h"
46
47 #if HAS_PTHREAD_SETNAME_NP
48 #if DEBUG
49 #define _GNU_SOURCE 1
50 #endif
51 #endif
52
53 #include <stdio.h>
54 #include <stdlib.h>
55
56 #include <time.h>
57 #include <signal.h>
58 #include <sys/types.h>
59 #include <sys/time.h>
60 #include <unistd.h>
61 #include <stddef.h>
62
63 #include <dnscore/thread.h>
64 #include <sys/mman.h>
65
66 #include "dnscore/logger_handle.h"
67 #include "dnscore/logger_channel_stream.h"
68 #include "dnscore/ptr_vector.h"
69 #include "dnscore/zalloc.h"
70
71 #include "dnscore/file_output_stream.h"
72 #include "dnscore/file_input_stream.h"
73 #include "dnscore/bytearray_output_stream.h"
74
75 #include "dnscore/format.h"
76 #include "dnscore/dnscore.h"
77 #include "dnscore/process.h"
78
79 #include "dnscore/async.h"
80
81 #include "dnscore/ptr_set.h"
82 #include "dnscore/thread_pool.h"
83
84 #if HAS_SHARED_QUEUE_SUPPORT
85 #include "dnscore/shared-circular-buffer.h"
86 #include "dnscore/shared-heap.h"
87 #include "dnscore/shared-heap-bytearray-output-stream.h"
88 #else
89 #include "dnscore/bytezarray_output_stream.h"
90 #include "dnscore/threaded_queue.h"
91 #include "dnscore/ipc.h"
92 #endif
93
94 #include "dnscore/buffer_output_stream.h"
95 #include "dnscore/buffer_input_stream.h"
96
97 #define LOGGER_HANDLE_TAG 0x4c444e48474f4c /* LOGHNDL */
98 #define LOGCHAN_TAG 0x4e414843474f4c /* LOGCHAN */
99
100 // If the logger thread queues a log message, and the log queue is full (ie: because the disk is full) a dead-lock may ensue.
101 // So queued-logging is to be avoided in the logger thread
102 // That being said, DEBUG_LOG_HANDLER and DEBUG_LOG_MESSAGES may trigger this issue as it is a debug, dev-only, feature.
103
104 #if DNSCORE_HAS_LOG_THREAD_TAG
105 void thread_tag_push_tags();
106 #endif
107
108 #define DEBUG_LOG_HANDLER 0 // can be: 0 1 2, don't use for production
109 #define DEBUG_LOG_MESSAGES 0
110 #define DEBUG_LOG_REGISTRATIONS 0
111
112 #if DEBUG_LOG_MESSAGES
113 # pragma message("DEBUG_LOG_MESSAGES") // the space after the '#' is to ignore it on #pragma search
114 #endif
115
116 #define COLUMN_SEPARATOR " | "
117 #define COLUMN_SEPARATOR_SIZE 3
118
119 #define MODULE_MSG_HANDLE g_system_logger
120
121 #define LOGRMSG_TAG 0x47534d52474f4c
122 #define LOGRTEXT_TAG 0x5458455452474f4c
123
124 struct logger_handle;
125
126 #define LOGGER_MESSAGE_TYPE_TEXT 0 // send a text to output
127 #define LOGGER_MESSAGE_TYPE_STOP 1 // stop the service
128 #define LOGGER_MESSAGE_TYPE_CHANNEL_FLUSH_ALL 2 // flush all channels
129 #define LOGGER_MESSAGE_TYPE_CHANNEL_REOPEN_ALL 3 // reopen all channels
130 #define LOGGER_MESSAGE_TYPE_CHANNEL_CLOSE_ALL 4 // close all channels
131 #define LOGGER_MESSAGE_TYPE_CHANNEL_SINK_ALL 5 // sink all channels
132 #define LOGGER_MESSAGE_TYPE_IGNORE 6 // no operation
133
134 #define LOGGER_MESSAGE_TYPE_CHANNEL_GET_USAGE_COUNT 7 // grabs the number of uses of the channel, or -1 if not registered
135 #define LOGGER_MESSAGE_TYPE_CHANNEL_REGISTER 8 // register a new channel
136 #define LOGGER_MESSAGE_TYPE_CHANNEL_UNREGISTER 9 // unregister a channel
137
138 #define LOGGER_MESSAGE_TYPE_HANDLE_CREATE 10 // open a new handle
139 #define LOGGER_MESSAGE_TYPE_HANDLE_CLOSE 11 // close a handle
140 #define LOGGER_MESSAGE_TYPE_HANDLE_NAME_ADD_CHANNEL 12 // add a channel to a handle identified by its name
141 #define LOGGER_MESSAGE_TYPE_HANDLE_NAME_REMOVE_CHANNEL 13 // remove a channel from a handle identified by its name
142 #define LOGGER_MESSAGE_TYPE_HANDLE_NAME_COUNT_CHANNELS 14 // return the number of channels linked to this logger
143
144 #define LOGGER_MESSAGE_TYPE_THREAD_SET_TAG 15 // sets the tag for a thread ( + pid)
145 #define LOGGER_MESSAGE_TYPE_THREAD_CLEAR_TAG 16 // clears the tag for a thread ( + pid)
146
147 #define LOGGER_DISPATCHED_THREAD_STOPPED 0
148 #define LOGGER_DISPATCHED_THREAD_STARTED 1
149 #define LOGGER_DISPATCHED_THREAD_READY 2
150 #define LOGGER_DISPATCHED_THREAD_STOPPING 3
151
152 #define LOGGER_MESSAGE_SINK_FAKE ((logger_message*) 1)
153
154 #define LOGGER_HANDLE_COUNT_MAX 16
155 #define LOGGER_HANDLE_SHARED_TABLE_SIZE (((sizeof(logger_handle) + 63) & ~63) * LOGGER_HANDLE_COUNT_MAX)
156
157 static smp_int logger_thread_state = SMP_INT_INITIALIZER;
158
159 struct logger_handle LOGGER_HANDLE_SINK_;
160
161 struct logger_handle *LOGGER_HANDLE_SINK_PTR = &LOGGER_HANDLE_SINK_;
162
163 static logger_handle *g_logger_handle_shared_table = NULL;
164
165 struct logger_handle LOGGER_HANDLE_SINK_ =
166 {
167 {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U},
168 {
169 PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY,
170 PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY,
171 PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY,
172 PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY
173 },
174 "SINK",
175 "sink",
176 4,
177 &LOGGER_HANDLE_SINK_PTR
178 #if DEBUG
179 , LOGGER_HANDLE_MAGIC_CHECK
180 #endif
181 };
182
183 struct logger_message_text_s
184 {
185 u8 type; // 0 0
186 u8 level; //
187 u16 flags; //
188 u16 text_length; //
189 u16 text_buffer_length; // align 64
190 struct logger_handle *handle; // 8 8
191
192 u8 *text; // 12 16
193
194 #if SIZEOF_TIMEVAL <= 8
195 struct timeval tv; // 16 24
196 #else
197 s64 timestamp;
198 #endif
199
200 const u8* prefix; // 24 32
201 u16 prefix_length; // 28 40
202 #if !HAS_SHARED_QUEUE_SUPPORT
203 s16 rc; // 30 42 reference count for the repeats
204
205 #if DEBUG || HAS_LOG_PID
206 pid_t pid; // 32 44
207 #endif
208 #endif
209
210 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
211 thread_t thread_id; // 36 48
212 #endif
213 // 40 56
214 };
215
216 struct logger_message_channel_flush_all_s
217 {
218 u8 type;
219 u8 val8;
220 u16 val16;
221 u32 val32; // align 64
222
223 async_wait_s *aw;
224
225 thread_t tid; // only used for debugging purposes
226 };
227
228 struct logger_message_channel_reopen_all_s
229 {
230 u8 type;
231 u8 val8;
232 u16 val16;
233 u32 val32; // align 64
234
235 async_wait_s *aw;
236 };
237
238 struct logger_message_channel_sink_all_s
239 {
240 u8 type;
241 u8 val8;
242 u16 val16;
243 u32 val32; // align 64
244
245 async_wait_s *aw;
246 };
247
248 struct logger_message_channel_get_usage_count_s
249 {
250 u8 type;
251 u8 val8;
252 u16 val16;
253 u32 val32; // align 64
254
255 async_wait_s *aw;
256 const char* channel_name;
257 s32 *countp;
258 };
259
260 struct logger_message_channel_register_s
261 {
262 u8 type;
263 u8 val8;
264 u16 val16;
265 u32 val32; // align 64
266
267 async_wait_s *aw;
268 const char* channel_name;
269 struct logger_channel *channel;
270 };
271
272 struct logger_message_channel_unregister_s
273 {
274 u8 type;
275 u8 val8;
276 u16 val16;
277 u32 val32; // align 64
278
279 async_wait_s *aw;
280 const char* channel_name;
281 };
282
283 /// @note no need for reopen
284
285 struct logger_message_stop_s
286 {
287 u8 type;
288 u8 val8;
289 u16 val16;
290 u32 val32; // align 64
291
292 async_wait_s *aw;
293 };
294
295 /// @note no need for ignore
296
297 struct logger_message_handle_create_s
298 {
299 u8 type;
300 u8 val8;
301 u16 val16;
302 u32 val32; // align 64
303
304 async_wait_s *aw;
305 const char *logger_name;
306 logger_handle **handle_holder;
307 };
308
309 struct logger_message_handle_close_s
310 {
311 u8 type;
312 u8 val8;
313 u16 val16;
314 u32 val32; // align 64
315
316 async_wait_s *aw;
317 const char *logger_name;
318 };
319
320 struct logger_message_handle_add_channel_s
321 {
322 u8 type;
323 u8 val8;
324 u16 val16;
325 u32 val32; // align 64
326
327 async_wait_s *aw;
328 const char *logger_name;
329 const char *channel_name;
330 u16 level;
331 };
332
333 struct logger_message_handle_remove_channel_s
334 {
335 u8 type;
336 u8 val8;
337 u16 val16;
338 u32 val32; // align 64
339
340 async_wait_s *aw;
341 const char *logger_name;
342 const char *channel_name;
343 };
344
345 struct logger_message_handle_count_channels_s
346 {
347 u8 type;
348 u8 val8;
349 u16 val16;
350 u32 val32; // align 64
351
352 async_wait_s *aw;
353 const char *logger_name;
354 s32 *countp;
355 };
356
357 #if DNSCORE_HAS_LOG_THREAD_TAG
358
359 struct logger_message_thread_set_tag_s
360 {
361 u8 type;
362 u8 val8;
363 u16 val16;
364 u32 val32; // align 64
365 async_wait_s *aw;
366 char tag[THREAD_TAG_SIZE];
367 thread_t tid;
368 };
369
370 struct logger_message_thread_clear_tag_s
371 {
372 u8 type;
373 u8 val8;
374 u16 val16;
375 u32 val32; // align 64
376 async_wait_s *aw;
377 thread_t tid;
378 };
379
380 #endif
381
382 struct logger_message
383 {
384 #if HAS_SHARED_QUEUE_SUPPORT
385 u8 reserved_for_the_queue;
386 u8 align0;
387 u16 align1;
388 pid_t pid; // 4 4
389 #endif
390 union
391 {
392 u8 type;
393 struct logger_message_text_s text;
394 struct logger_message_stop_s stop;
395 // no specific data for ignore
396 struct logger_message_channel_flush_all_s channel_flush_all;
397 struct logger_message_channel_reopen_all_s channel_reopen_all;
398 struct logger_message_channel_sink_all_s channel_sink_all;
399 struct logger_message_channel_get_usage_count_s get_usage_count;
400 struct logger_message_channel_register_s channel_register;
401 struct logger_message_channel_unregister_s channel_unregister;
402 struct logger_message_handle_create_s handle_create;
403 struct logger_message_handle_close_s handle_close;
404 struct logger_message_handle_add_channel_s handle_add_channel;
405 struct logger_message_handle_remove_channel_s handle_remove_channel;
406 struct logger_message_handle_count_channels_s handle_count_channels;
407 #if DNSCORE_HAS_LOG_THREAD_TAG
408 struct logger_message_thread_set_tag_s thread_set_tag;
409 struct logger_message_thread_clear_tag_s thread_clear_tag;
410 #endif
411 };
412 };
413
414 typedef struct logger_message logger_message;
415
416 /// tree set initialised empty with a comparator for ASCIIZ char* keys
417 static ptr_set logger_channels = PTR_SET_ASCIIZ_EMPTY;
418 static ptr_vector logger_handles = PTR_VECTOR_EMPTY;
419 static mutex_t logger_mutex = MUTEX_INITIALIZER;
420
421 #if HAS_SHARED_QUEUE_SUPPORT
422 struct shared_circular_buffer* logger_shared_queue = NULL;
423 #else
424 static threaded_queue logger_commit_queue = THREADED_QUEUE_EMPTY;
425 #endif
426
427 struct logger_shared_space_s
428 {
429 logger_message *_logger_sink_request_message;
430 logger_message *_logger_reopen_request_message;
431 };
432
433 typedef struct logger_shared_space_s logger_shared_space_t;
434
435 static logger_shared_space_t logger_shared_space_null = {NULL, NULL};
436
437 static logger_shared_space_t *logger_shared_space = &logger_shared_space_null;
438
439 static thread_t logger_thread_id = 0;
440 static pid_t logger_thread_pid = -1;
441 static u32 exit_level = MSG_CRIT;
442 static const char acewnid[16 + 1] = "!ACEWNID1234567";
443
444 static volatile pid_t logger_handle_owner_pid = 0;
445 static volatile bool _logger_started = FALSE;
446 static volatile bool _logger_initialised = FALSE;
447 #if !HAS_SHARED_QUEUE_SUPPORT
448 static volatile bool logger_is_client = FALSE;
449 #endif
450 static volatile bool logger_queue_initialised = FALSE;
451 static volatile bool logger_handle_init_done = FALSE;
452 static volatile u8 logger_level = MSG_ALL;
453 static u8 logger_shared_heap_id = 0;
454
logger_initialised()455 static bool logger_initialised()
456 {
457 mutex_lock(&logger_mutex);
458 bool ret = _logger_initialised;
459 mutex_unlock(&logger_mutex);
460 return ret;
461 }
462
logger_started()463 static bool logger_started()
464 {
465 mutex_lock(&logger_mutex);
466 bool ret = _logger_started;
467 mutex_unlock(&logger_mutex);
468 return ret;
469 }
470
logger_initialised_and_started()471 static bool logger_initialised_and_started()
472 {
473 mutex_lock(&logger_mutex);
474 bool ret = _logger_started && _logger_initialised;
475 mutex_unlock(&logger_mutex);
476 return ret;
477 }
478
479 #if DEBUG_LOG_MESSAGES
480 static smp_int allocated_messages_count = SMP_INT_INITIALIZER;
481 static time_t allocated_messages_count_stats_time = 0;
482 #endif
483
logger_handle_trigger_emergency_shutdown()484 static void logger_handle_trigger_emergency_shutdown()
485 {
486 flusherr();
487 logger_flush();
488 abort();
489 }
490
491 /*******************************************************************************
492 *
493 * Logger message functions
494 *
495 *******************************************************************************/
496
497 static inline logger_message*
logger_message_alloc()498 logger_message_alloc()
499 {
500 #ifdef NDEBUG
501 size_t sizeof_logger_message = sizeof(logger_message);
502 assert(sizeof_logger_message <= 64);
503 (void)sizeof_logger_message;
504 #endif
505 logger_message* message;
506 #if HAS_SHARED_QUEUE_SUPPORT
507 message = (logger_message*)shared_circular_buffer_prepare_enqueue(logger_shared_queue);
508 #if DEBUG
509 memset(((u8*)message) + 1, 'Q', sizeof(logger_message) - 1);
510 #endif
511 #else
512 ZALLOC_OBJECT_OR_DIE( message, logger_message, LOGRMSG_TAG);
513 #if DEBUG
514 memset(message, 'Q', sizeof(logger_message));
515 #endif
516 #endif
517
518 #if DEBUG_LOG_MESSAGES
519 smp_int_inc(&allocated_messages_count);
520 #endif
521
522 return message;
523 }
524
525 #if HAS_SHARED_QUEUE_SUPPORT
526 static inline logger_message*
logger_message_try_alloc()527 logger_message_try_alloc()
528 {
529 logger_message* message;
530 message = (logger_message*)shared_circular_buffer_try_prepare_enqueue(logger_shared_queue);
531 #if DEBUG
532 if(message != NULL)
533 {
534 memset(&((u8*)message)[1], 'q', sizeof(logger_message) - 1);
535 }
536 #endif
537 return message;
538 }
539 #endif
540
541 #if !HAS_SHARED_QUEUE_SUPPORT
542 static inline void
logger_message_free(logger_message * message)543 logger_message_free(logger_message *message)
544 {
545 ZFREE_OBJECT(message);
546
547 #if DEBUG_LOG_MESSAGES
548 smp_int_dec(&allocated_messages_count);
549 #endif
550 }
551 #endif
552
553 static inline void
logger_message_post(void * message)554 logger_message_post(void* message)
555 {
556 #if HAS_SHARED_QUEUE_SUPPORT
557 shared_circular_buffer_commit_enqueue(logger_shared_queue, message);
558 #else
559 threaded_queue_enqueue(&logger_commit_queue, message);
560 #endif
561 }
562
563 /*******************************************************************************
564 *
565 * Logger handle functions
566 *
567 *******************************************************************************/
568
569 static ya_result logger_service_handle_remove_channel(logger_handle *handle, const char *channel_name);
570 static void logger_service_handle_remove_all_channel(logger_handle *handle);
571
572 /**
573 * Returns true iff the current thread is the logger.
574 *
575 * @return true iff the current thread is the logger.
576 */
577
578 bool
logger_is_self()579 logger_is_self()
580 {
581 return logger_thread_id == thread_self();
582 }
583
584 #if 0
585 static int
586 logger_handle_compare(const void* a, const void* b)
587 {
588 logger_handle* ha = (logger_handle*)a;
589 logger_handle* hb = (logger_handle*)b;
590
591 if(ha == hb)
592 {
593 return 0;
594 }
595
596 return strcmp(ha->name, hb->name);
597 }
598 #endif
599
600 static int
logger_handle_compare_match(const void * key,const void * value)601 logger_handle_compare_match(const void* key, const void* value)
602 {
603 const char* hkey = (const char*)key;
604 const logger_handle* hvalue = (const logger_handle*)value;
605
606 return strcmp(hkey, hvalue->name);
607 }
608
609 static void
logger_handle_free(void * ptr)610 logger_handle_free(void* ptr)
611 {
612 logger_handle* handle = (logger_handle*)ptr;
613
614 #if DEBUG_LOG_HANDLER
615 debug_osformatln(termout, "logger_handle_free(%s@%p)", handle->name, ptr);
616 flushout();
617 #endif
618
619 logger_service_handle_remove_all_channel(handle);
620
621 for(u8 lvl = 0; lvl < MSG_LEVEL_COUNT; lvl++)
622 {
623 ptr_vector_destroy(&handle->channels[lvl]);
624 }
625
626 if(handle->global_reference == NULL)
627 {
628 debug_osformatln(termerr, "bug: logger handle '%s' must be initialised to LOGGER_HANDLE_SINK but is set to NULL", handle->name);
629 flusherr();
630 abort();
631 return;
632 }
633
634 if(*handle->global_reference != LOGGER_HANDLE_SINK)
635 {
636 *handle->global_reference = LOGGER_HANDLE_SINK;
637 }
638
639 #if DEBUG
640 memset((char*)handle->formatted_name, 0xfe, strlen(handle->formatted_name));
641 #endif
642 #if !HAS_SHARED_QUEUE_SUPPORT
643 free((char*)handle->formatted_name);
644 #endif
645 #if DEBUG
646 memset((char*)handle->name, 0xfe, strlen(handle->name));
647 #endif
648 #if !HAS_SHARED_QUEUE_SUPPORT
649 free((char*)handle->name);
650 #endif
651 #if DEBUG
652 memset(handle, 0xfe, sizeof(logger_handle));
653 #endif
654 #if HAS_SHARED_QUEUE_SUPPORT
655 //shared_heap_free(handle);
656 #else
657 free(handle);
658 #endif
659 }
660
661 /*******************************************************************************
662 *
663 * Logger channel functions
664 *
665 *******************************************************************************/
666
667 #define LOGGER_CHANNEL_COUNT_MAX 128
668
669 static logger_channel* logger_channel_shared_memory = NULL;
670 static size_t logger_channel_shared_memory_avail = 0;
671 static u8 logger_channel_allocated[LOGGER_CHANNEL_COUNT_MAX/8];
672
logger_channel_shared_memory_size()673 static inline size_t logger_channel_shared_memory_size()
674 {
675 return (LOGGER_CHANNEL_COUNT_MAX * sizeof(logger_channel) + 0xfff) & ~0xfff;
676 }
677
678 logger_channel*
logger_channel_alloc()679 logger_channel_alloc()
680 {
681 if(logger_handle_owner_pid == 0) // don't know our pid yet
682 {
683 logger_handle_owner_pid = getpid_ex(); // update it, set us as the logger process
684 }
685 else if(logger_handle_owner_pid != getpid_ex()) // if we are not the logger process, this is very wrong
686 {
687 // no can do
688 debug_osformatln(termerr, "logger_channel_alloc() cannot be called from this process");
689 return NULL;
690 }
691
692 if(logger_channel_shared_memory == NULL)
693 {
694 void *ptr = mmap(NULL, logger_channel_shared_memory_size(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
695
696 if(ptr == MAP_FAILED)
697 {
698 int err = ERRNO_ERROR;
699 debug_osformatln(termerr, "logger_channel_alloc() shared memory allocation failed: %r", err);
700 return NULL;
701 }
702
703 yassert(ptr != NULL);
704
705 logger_channel_shared_memory = (logger_channel*)ptr;
706
707 memset(logger_channel_shared_memory, 0U, logger_channel_shared_memory_size());
708 logger_channel_shared_memory_avail = logger_channel_shared_memory_size() / sizeof(logger_channel);
709
710 memset(logger_channel_allocated, 0U, sizeof(logger_channel_allocated));
711 }
712
713 logger_channel* chan;
714
715 #if DEBUG_LOG_HANDLER
716 debug_osformatln(termout, "logger_channel_alloc()");
717 flushout();
718 #endif
719
720 if(logger_channel_shared_memory_avail == 0)
721 {
722 return NULL;
723 }
724
725 chan = NULL;
726
727 for(int i = 0; i < LOGGER_CHANNEL_COUNT_MAX/8; ++i)
728 {
729 if(logger_channel_allocated[i] != MAX_U8)
730 {
731 for(int j = 0; j < 8; ++j)
732 {
733 if((logger_channel_allocated[i] & (1 << j)) == 0)
734 {
735 logger_channel_allocated[i] |= 1 << j;
736 chan = &logger_channel_shared_memory[(i << 3) + j];
737
738 chan->data = NULL;
739 chan->vtbl = NULL;
740
741 #if !HAS_SHARED_QUEUE_SUPPORT
742 /* dummy to avoid a NULL test */
743 logger_message* last_message = logger_message_alloc();
744 last_message->pid = getpid_ex();
745 last_message->type = LOGGER_MESSAGE_TYPE_TEXT;
746 ZALLOC_ARRAY_OR_DIE(u8*, last_message->text.text, 1, LOGRTEXT_TAG);
747 *last_message->text.text = '\0';
748 last_message->text.text_length = 1;
749 last_message->text.text_buffer_length = 1;
750 last_message->text.flags = 0;
751 last_message->text.rc = 1;
752 last_message->text.thread_id = thread_self();
753
754 chan->last_message = last_message;
755 chan->last_message_count = 0;
756 #endif
757 chan->linked_handles = 0;
758 return chan;
759 }
760 }
761 }
762 }
763
764 return NULL;
765 }
766
767 static void
logger_channel_free(logger_channel * channel)768 logger_channel_free(logger_channel *channel)
769 {
770 if((channel == NULL) || (channel < logger_channel_shared_memory))
771 {
772 return;
773 }
774
775 #if DEBUG_LOG_HANDLER
776 debug_osformatln(termout, "logger_channel_free(%p), linked to %d", channel, channel->linked_handles);
777 flushout();
778 #endif
779
780 size_t slot = (channel - logger_channel_shared_memory);
781 if(slot > (sizeof(logger_channel_allocated) * 8))
782 {
783 return;
784 }
785
786 if((logger_channel_allocated[slot >> 3] & (1 << (slot & 7))) == 0)
787 {
788 return;
789 }
790
791 assert(channel->linked_handles == 0); // don't yassert
792 assert(logger_handle_owner_pid == getpid_ex());
793
794 #if !HAS_SHARED_QUEUE_SUPPORT
795 logger_message* last_message = channel->last_message;
796
797 if(--last_message->text.rc == 0)
798 {
799 ZFREE_ARRAY(last_message->text.text, last_message->text.text_buffer_length);
800 logger_message_free(last_message);
801 }
802 #endif
803 if(channel->vtbl != NULL)
804 {
805 logger_channel_close(channel);
806 channel->vtbl = NULL;
807 }
808
809 logger_channel_allocated[slot >> 3] &= ~(1 << (slot & 7));
810 ++logger_channel_shared_memory_avail;
811 }
812
813 static logger_channel*
logger_service_channel_get(const char * channel_name)814 logger_service_channel_get(const char *channel_name)
815 {
816 logger_channel *channel = NULL;
817
818 ptr_node *node = ptr_set_find(&logger_channels, channel_name);
819 if(node != NULL)
820 {
821 channel = (logger_channel*)node->value;
822 }
823
824 #if DEBUG_LOG_HANDLER
825 debug_osformatln(termout, "logger_service_channel_get(%s) = %p", channel_name, channel);
826 flushout();
827 #endif
828
829 return channel;
830 }
831
832 static ya_result
logger_service_channel_register(const char * channel_name,logger_channel * channel)833 logger_service_channel_register(const char *channel_name, logger_channel *channel)
834 {
835 #if DEBUG_LOG_HANDLER
836 debug_osformatln(termout, "logger_service_channel_register(%s,%p)", channel_name, channel);
837 flushout();
838 #endif
839
840 if(channel->linked_handles != 0)
841 {
842 #if DEBUG_LOG_HANDLER
843 debug_osformatln(termout, "logger_service_channel_register(%s,%p) ALREADY LINKED", channel_name, channel);
844 flushout();
845 #endif
846 return LOGGER_CHANNEL_HAS_LINKS;
847 }
848
849 if(logger_service_channel_get(channel_name) != NULL)
850 {
851 #if DEBUG_LOG_HANDLER
852 debug_osformatln(termout, "logger_service_channel_register(%s,%p) NAME ALREADY USED", channel_name, channel);
853 flushout();
854 #endif
855 logger_channel_free(channel);
856 return LOGGER_CHANNEL_ALREADY_REGISTERED;
857 }
858
859 ptr_node *node = ptr_set_insert(&logger_channels, strdup(channel_name));
860 node->value = channel;
861
862 return SUCCESS;
863 }
864
865 static ya_result
logger_service_channel_unregister(const char * channel_name)866 logger_service_channel_unregister(const char *channel_name)
867 {
868 #if DEBUG_LOG_HANDLER
869 debug_osformatln(termout, "logger_service_channel_unregister(%s)", channel_name);
870 flushout();
871 #endif
872
873 logger_channel *channel;
874
875 ptr_node *node = ptr_set_find(&logger_channels, channel_name);
876
877 if(node == NULL)
878 {
879 #if DEBUG_LOG_HANDLER
880 debug_osformatln(termout, "logger_service_channel_unregister(%s) NAME NOT USED", channel_name);
881 flushout();
882 #endif
883 return LOGGER_CHANNEL_NOT_REGISTERED;
884 }
885
886 channel = (logger_channel*)node->value;
887
888 if(channel->linked_handles != 0)
889 {
890 #if DEBUG_LOG_HANDLER
891 debug_osformatln(termout, "logger_service_channel_unregister(%s) STILL LINKED", channel_name);
892 flushout();
893 #endif
894 return LOGGER_CHANNEL_HAS_LINKS;
895 }
896
897 char *key = (char*)node->key;
898 ptr_set_delete(&logger_channels, channel_name);
899 free(key);
900
901 // remove the channel from all the handles
902
903 for(s32 i = 0; i < ptr_vector_size(&logger_handles); i++)
904 {
905 logger_handle *handle = (logger_handle*)ptr_vector_get(&logger_handles, i);
906 logger_service_handle_remove_channel(handle, channel_name);
907 }
908
909 logger_channel_free(channel);
910
911 return SUCCESS;
912 }
913
914 static void
logger_service_channel_unregister_all()915 logger_service_channel_unregister_all()
916 {
917 #if DEBUG_LOG_HANDLER
918 debug_osformatln(termout, "logger_service_channel_unregister_all()");
919 flushout();
920 #endif
921
922 // for all channels
923
924 ptr_vector logger_channel_list = PTR_VECTOR_EMPTY;
925 ptr_vector logger_name_list = PTR_VECTOR_EMPTY;
926
927 ptr_set_iterator iter;
928 ptr_set_iterator_init(&logger_channels, &iter);
929 while(ptr_set_iterator_hasnext(&iter))
930 {
931 ptr_node *node = ptr_set_iterator_next_node(&iter);
932
933 logger_channel *channel = (logger_channel*)node->value;
934 char *channel_name = (char*)node->key;
935
936 ptr_vector_append(&logger_name_list, channel_name);
937 ptr_vector_append(&logger_channel_list, channel);
938 }
939
940 for(int i = 0; i <= ptr_vector_last_index(&logger_name_list); ++i)
941 {
942 char *channel_name = (char*)ptr_vector_get(&logger_name_list, i);
943
944 #if DEBUG_LOG_HANDLER
945 logger_channel *channel = (logger_channel*)ptr_vector_get(&logger_channel_list, i);
946 debug_osformatln(termout, "logger_service_channel_unregister_all() : channel %s@%p", channel_name, channel);
947 flushout();
948 #endif
949
950 // for all handles
951
952 for(s32 i = 0; i <= ptr_vector_last_index(&logger_handles); i++)
953 {
954 logger_handle *handle = (logger_handle*)ptr_vector_get(&logger_handles, i);
955
956 #if DEBUG_LOG_HANDLER
957 debug_osformatln(termout, "logger_service_channel_unregister_all() : channel %s@%p : handle %s@%p", channel_name, channel, handle->name, handle);
958 flushout();
959 #endif
960
961 // remove channel from handle
962
963 logger_service_handle_remove_channel(handle, channel_name);
964 }
965
966 #if DEBUG_LOG_HANDLER
967 assert(channel->linked_handles == 0);
968 #endif
969 }
970
971 for(int i = 0; i <= ptr_vector_last_index(&logger_name_list); ++i)
972 {
973 char *channel_name = (char*)ptr_vector_get(&logger_name_list, i);
974 logger_channel *channel = (logger_channel*)ptr_vector_get(&logger_channel_list, i);
975
976 logger_channel_free(channel);
977 free(channel_name);
978 }
979
980 ptr_set_destroy(&logger_channels);
981
982 ptr_vector_destroy(&logger_channel_list);
983 ptr_vector_destroy(&logger_name_list);
984 }
985
986 /**
987 * Used to find a channel in the channel array in a handle
988 */
989
990 static int
logger_handle_channel_compare_match(const void * a,const void * b)991 logger_handle_channel_compare_match(const void *a, const void *b)
992 {
993 const logger_channel* channel_a = (const logger_channel*)a;
994 const logger_channel* channel_b = (const logger_channel*)b;
995
996 if(channel_a == channel_b)
997 {
998 return 0;
999 }
1000
1001 return 1;
1002 }
1003
1004 /**
1005 * INTERNAL: used by the service
1006 */
1007
1008 static logger_handle*
logger_service_handle_create(const char * name)1009 logger_service_handle_create(const char *name)
1010 {
1011 #if DEBUG_LOG_HANDLER
1012 debug_osformatln(termout, "[%i] logger_service_handle_create(%s)", getpid(), name);
1013 flushout();
1014 #endif
1015
1016 size_t name_len = strlen(name);
1017
1018 if(name_len > LOGGER_HANDLE_NAME_SIZE_MAX)
1019 {
1020 #if DEBUG_LOG_HANDLER
1021 debug_osformatln(termout, "[%i] logger_service_handle_create(%s) : name is too big", getpid(), name);
1022 flushout();
1023 #endif
1024 return NULL;
1025 }
1026
1027 logger_handle* handle = (logger_handle*)ptr_vector_linear_search(&logger_handles, name, logger_handle_compare_match);
1028
1029 if(handle == NULL)
1030 {
1031 s32 handle_index = ptr_vector_size(&logger_handles);
1032
1033 assert(handle_index < LOGGER_HANDLE_COUNT_MAX);
1034
1035 handle = &g_logger_handle_shared_table[handle_index];
1036
1037 memcpy(handle->name, name, name_len + 1);
1038 memset(handle->formatted_name, ' ', LOGGER_HANDLE_FORMATTED_NAME_SIZE_MAX);
1039 memcpy(handle->formatted_name, name, MIN(name_len, LOGGER_HANDLE_FORMATTED_NAME_SIZE_MAX));
1040 handle->formatted_name[LOGGER_HANDLE_FORMATTED_NAME_SIZE_MAX] = '\0';
1041
1042 handle->enabled = TRUE;
1043
1044 #if DEBUG
1045 handle->magic_check = LOGGER_HANDLE_MAGIC_CHECK;
1046 #endif
1047 int i;
1048
1049 for(i = 0; i < MSG_LEVEL_COUNT; i++)
1050 {
1051 handle->active[i] = 0;
1052 ptr_vector_init(&handle->channels[i]);
1053 }
1054
1055 ptr_vector_append(&logger_handles, handle); // this is a collection to keep track of the handles, not their storage
1056 }
1057 else
1058 {
1059 if(handle->enabled)
1060 {
1061 #if DEBUG_LOG_HANDLER
1062 debug_osformatln(termerr, "[%i] logger_service_handle_create(%s) : handle already created at %p", getpid(), name, handle);
1063 flusherr();
1064 #endif
1065 }
1066 else
1067 {
1068 handle->enabled = TRUE;
1069 }
1070 }
1071
1072 #if DEBUG_LOG_HANDLER
1073 debug_osformatln(termout, "[%i] logger_service_handle_create(%s) = %p", getpid(), name, handle);
1074 flushout();
1075 #endif
1076
1077 return handle;
1078 }
1079
1080 static void
logger_service_handle_close(const char * name)1081 logger_service_handle_close(const char *name)
1082 {
1083 #if DEBUG_LOG_HANDLER
1084 debug_osformatln(termout, "logger_service_handle_close(%s)", name);
1085 flushout();
1086 #endif
1087
1088 //logger_handle* handle = (logger_handle*)ptr_vector_search(&logger_handles, name, logger_handle_compare_match);
1089 logger_handle* handle = (logger_handle*)ptr_vector_linear_search(&logger_handles, name, logger_handle_compare_match);
1090
1091 if(handle != NULL)
1092 {
1093 if(!handle->enabled)
1094 {
1095 return;
1096 }
1097
1098 if(*handle->global_reference != LOGGER_HANDLE_SINK)
1099 {
1100 *handle->global_reference = LOGGER_HANDLE_SINK; // but the handle will still exist, only disabled
1101 }
1102
1103 // decrement references for all channels used
1104
1105 memset(handle->active, 0, sizeof(handle->active));
1106
1107 for(int lvl = 0; lvl < MSG_LEVEL_COUNT; lvl++)
1108 {
1109 for(s32 idx = 0; idx < ptr_vector_size(&handle->channels[lvl]); idx++)
1110 {
1111 logger_channel *channel = (logger_channel*)ptr_vector_get(&handle->channels[lvl], idx);
1112 ptr_vector_end_swap(&handle->channels[lvl], idx);
1113 ptr_vector_pop(&handle->channels[lvl]);
1114 channel->linked_handles--;
1115 }
1116
1117 ptr_vector_destroy(&handle->channels[lvl]);
1118 }
1119
1120 handle->enabled = FALSE;
1121 }
1122 // else the handle never existed
1123 }
1124
1125 #if 0
1126 static void
1127 logger_service_handle_close_all()
1128 {
1129 }
1130 #endif
1131
1132 static inline logger_handle*
logger_service_handle_get(const char * name)1133 logger_service_handle_get(const char *name)
1134 {
1135 logger_handle* handle = (logger_handle*)ptr_vector_linear_search(&logger_handles, name, logger_handle_compare_match);
1136
1137 if((handle != NULL) && (!handle->enabled))
1138 {
1139 handle = NULL;
1140 }
1141
1142 return handle;
1143 }
1144
1145 /**
1146 * INTERNAL: used by the service
1147 */
1148
1149 static ya_result
logger_service_handle_add_channel(logger_handle * handle,int level,const char * channel_name)1150 logger_service_handle_add_channel(logger_handle *handle, int level, const char *channel_name)
1151 {
1152 #if DEBUG_LOG_HANDLER
1153 debug_osformatln(termout, "logger_service_handle_add_channel(%s@%p, %x, %s)", handle->name, handle, level, channel_name);
1154 flushout();
1155 #endif
1156
1157 assert(level >= 0 && level <= MSG_ALL_MASK);
1158
1159 int lvl;
1160 int level_mask;
1161
1162 logger_channel *channel = logger_service_channel_get(channel_name);
1163
1164 if(channel == NULL)
1165 {
1166 #if DEBUG_LOG_HANDLER
1167 debug_osformatln(termout, "logger_service_handle_add_channel(%s@%p, %x, %s) UNKNOWN CHANNEL", handle->name, handle, level, channel_name);
1168 flushout();
1169 #endif
1170
1171 return LOGGER_CHANNEL_NOT_REGISTERED;
1172 }
1173
1174 // add the channel in every level required by the level mask
1175
1176 for(lvl = 0U, level_mask = 1; level_mask <= MSG_ALL_MASK; lvl++, level_mask <<= 1)
1177 {
1178 if((level & level_mask) != 0)
1179 {
1180 if(ptr_vector_linear_search(&handle->channels[lvl], channel, logger_handle_channel_compare_match) == NULL)
1181 {
1182 ptr_vector_append(&handle->channels[lvl], channel);
1183 channel->linked_handles++;
1184 handle->active[lvl] = 1;
1185 }
1186 }
1187 }
1188
1189 return SUCCESS;
1190 }
1191
1192 static ya_result
logger_service_handle_remove_channel(logger_handle * handle,const char * channel_name)1193 logger_service_handle_remove_channel(logger_handle *handle, const char *channel_name)
1194 {
1195 #if DEBUG_LOG_HANDLER
1196 debug_osformatln(termout, "logger_service_handle_remove_channel(%s@%p, %s)", handle->name, handle, channel_name);
1197 flushout();
1198 #endif
1199
1200 logger_channel *channel = logger_service_channel_get(channel_name);
1201 if(channel == NULL)
1202 {
1203 #if DEBUG_LOG_HANDLER
1204 debug_osformatln(termout, "logger_service_handle_remove_channel(%s@%p, %s) UNKNOWN CHANNEL", handle->name, handle, channel_name);
1205 flushout();
1206 #endif
1207
1208 return LOGGER_CHANNEL_NOT_REGISTERED;
1209 }
1210
1211 for(u8 lvl = 0; lvl <= MSG_ALL; lvl++)
1212 {
1213 s32 idx = ptr_vector_index_of(&handle->channels[lvl], channel, logger_handle_channel_compare_match);
1214
1215 if(idx >= 0)
1216 {
1217 ptr_vector_end_swap(&handle->channels[lvl], idx);
1218 ptr_vector_pop(&handle->channels[lvl]);
1219 channel->linked_handles--;
1220
1221 if(ptr_vector_isempty(&handle->channels[lvl]))
1222 {
1223 handle->active[lvl] = 0;
1224 }
1225 }
1226 }
1227
1228 return SUCCESS;
1229 }
1230
1231 static void
logger_service_handle_remove_all_channel(logger_handle * handle)1232 logger_service_handle_remove_all_channel(logger_handle *handle)
1233 {
1234 #if DEBUG_LOG_HANDLER
1235 debug_osformatln(termout, "logger_service_handle_remove_all_channel(%s@%p)", handle->name, handle);
1236 flushout();
1237 #endif
1238 memset(handle->active, 0, sizeof(handle->active));
1239
1240 for(u8 lvl = 0; lvl < MSG_LEVEL_COUNT; lvl++)
1241 {
1242 for(s32 idx = 0; idx < ptr_vector_size(&handle->channels[lvl]); idx++)
1243 {
1244 logger_channel *channel = (logger_channel*)ptr_vector_get(&handle->channels[lvl], idx);
1245 channel->linked_handles--;
1246 }
1247 ptr_vector_clear(&handle->channels[lvl]);
1248 }
1249 }
1250
1251 static ya_result
logger_service_handle_count_channels(logger_handle * handle)1252 logger_service_handle_count_channels(logger_handle *handle)
1253 {
1254 #if DEBUG_LOG_HANDLER
1255 debug_osformatln(termout, "logger_service_handle_count_channels(%s@%p)", handle->name, handle);
1256 flushout();
1257 #endif
1258
1259 s32 sum = 0;
1260
1261 for(u8 lvl = 0; lvl <= MSG_ALL; lvl++)
1262 {
1263 sum += ptr_vector_size(&handle->channels[lvl]);
1264 }
1265
1266 return sum;
1267 }
1268
1269 /**
1270 * INTERNAL: used inside the service (2)
1271 */
1272
1273 static void
logger_service_flush_all_channels()1274 logger_service_flush_all_channels()
1275 {
1276 #if DEBUG_LOG_HANDLER > 1
1277 debug_osformatln(termout, "logger_service_flush_all_channels()");
1278 flushout();
1279 #endif
1280
1281 ptr_set_iterator iter;
1282 ptr_set_iterator_init(&logger_channels, &iter);
1283 while(ptr_set_iterator_hasnext(&iter))
1284 {
1285 ptr_node *node = ptr_set_iterator_next_node(&iter);
1286 logger_channel *channel = (logger_channel*)node->value;
1287 logger_channel_flush(channel);
1288 }
1289 }
1290
1291 /**
1292 * INTERNAL: used inside the service (1)
1293 */
1294
1295 static void
logger_service_reopen_all_channels()1296 logger_service_reopen_all_channels()
1297 {
1298 #if DEBUG_LOG_HANDLER
1299 debug_osformatln(termout, "logger_service_reopen_all_channels()");
1300 flushout();
1301 #endif
1302 ptr_set_iterator iter;
1303 ptr_set_iterator_init(&logger_channels, &iter);
1304 while(ptr_set_iterator_hasnext(&iter))
1305 {
1306 ptr_node *node = ptr_set_iterator_next_node(&iter);
1307 logger_channel *channel = (logger_channel*)node->value;
1308 ya_result return_code = logger_channel_reopen(channel);
1309
1310 if(FAIL(return_code))
1311 {
1312 log_try_err("could not reopen logger channel '%s': %r", STRNULL((char*)node->key), return_code);
1313 }
1314 }
1315 }
1316
1317 /**
1318 * INTERNAL: used inside the service (1)
1319 */
1320
1321 static void
logger_service_sink_all_channels()1322 logger_service_sink_all_channels()
1323 {
1324 #if DEBUG_LOG_HANDLER
1325 debug_osformatln(termout, "logger_service_sink_all_channels()");
1326 flushout();
1327 #endif
1328 ptr_set_iterator iter;
1329 ptr_set_iterator_init(&logger_channels, &iter);
1330 while(ptr_set_iterator_hasnext(&iter))
1331 {
1332 ptr_node *node = ptr_set_iterator_next_node(&iter);
1333 logger_channel *channel = (logger_channel*)node->value;
1334 logger_channel_sink(channel);
1335 }
1336 }
1337
1338 /**
1339 *
1340 * Create the handle tables
1341 *
1342 * INTERNAL: used at initialisation the service
1343 */
1344
1345 void
logger_handle_exit_level(u32 level)1346 logger_handle_exit_level(u32 level)
1347 {
1348 if(level <= MSG_CRIT)
1349 {
1350 debug_osformatln(termerr, "message level too low: %u < %u", level, MSG_CRIT);
1351 flusherr();
1352 return;
1353 }
1354
1355 exit_level = level;
1356 }
1357
1358 #if !HAS_SHARED_QUEUE_SUPPORT
1359 static void*
logger_client_dispatcher_thread(void * context)1360 logger_client_dispatcher_thread(void* context)
1361 {
1362 #if DNSCORE_HAS_LOG_THREAD_TAG
1363 static char loggercl_thread_tag[9] = "loggercl";
1364 logger_handle_set_thread_tag(loggercl_thread_tag);
1365 #endif
1366
1367 int sockfd;
1368
1369 for(;;)
1370 {
1371 if((sockfd = ipc_client_connect("logger")) >= 0)
1372 {
1373 break;
1374 }
1375 }
1376
1377 output_stream los;
1378 input_stream lis;
1379
1380 fd_output_stream_attach_noclose(&los, sockfd);
1381 //buffer_output_stream_init(&los, &los, 4096);
1382 fd_input_stream_attach_noclose(&lis, sockfd);
1383
1384 bool must_run = TRUE;
1385
1386 while(must_run)
1387 {
1388 logger_message* message = (logger_message*)threaded_queue_try_dequeue(&logger_commit_queue);
1389
1390 if(message == NULL)
1391 {
1392 output_stream_flush(&los);
1393 sleep(1);
1394 continue;
1395 }
1396
1397 switch(message->type)
1398 {
1399 case LOGGER_MESSAGE_TYPE_TEXT:
1400 {
1401 struct logger_message_text_s *logger_message_text = (struct logger_message_text_s*)message;
1402 output_stream_write(&los, logger_message_text, offsetof(struct logger_message_text_s, text));
1403 output_stream_write(&los, &logger_message_text->tv, sizeof(struct logger_message_text_s) - offsetof(struct logger_message_text_s, tv));
1404 int len = strlen((const char*)logger_message_text->text);
1405 output_stream_write_u16(&los, len);
1406 output_stream_write(&los, logger_message_text->text, len);
1407 ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
1408 logger_message_free(message);
1409 break;
1410 }
1411
1412 case LOGGER_MESSAGE_TYPE_STOP:
1413 {
1414 must_run = threaded_queue_size(&logger_commit_queue) > 0;
1415 if(must_run)
1416 {
1417 // repost
1418 logger_message_post(message);
1419 break;
1420 }
1421
1422 u8 tmp;
1423 output_stream_write_u8(&los, message->type);
1424 input_stream_read_u8(&lis, &tmp);
1425 // process the sync (flush + process)
1426 async_wait_s *awp = message->stop.aw;
1427 logger_message_free(message);
1428 async_wait_progress(awp, 1);
1429
1430 break;
1431 }
1432
1433 case LOGGER_MESSAGE_TYPE_CHANNEL_FLUSH_ALL:
1434 case LOGGER_MESSAGE_TYPE_CHANNEL_REOPEN_ALL:
1435 case LOGGER_MESSAGE_TYPE_CHANNEL_CLOSE_ALL:
1436 case LOGGER_MESSAGE_TYPE_CHANNEL_SINK_ALL:
1437 {
1438 u8 tmp;
1439 output_stream_write_u8(&los, message->type);
1440 input_stream_read_u8(&lis, &tmp);
1441 // process the sync (flush + process)
1442 async_wait_s *awp = message->channel_flush_all.aw;
1443 logger_message_free(message);
1444 async_wait_progress(awp, 1);
1445
1446 break;
1447 }
1448
1449 case LOGGER_MESSAGE_TYPE_IGNORE:
1450 {
1451 logger_message_free(message);
1452 break;
1453 }
1454
1455 default:
1456 {
1457 abort();
1458 break;
1459 }
1460 }
1461 }
1462
1463 output_stream_close(&los);
1464 input_stream_close(&lis);
1465
1466 ipc_client_close(sockfd);
1467 logger_started = FALSE;
1468
1469 return NULL;
1470 }
1471
1472 static void*
logger_server_dispatcher_client_thread(void * context)1473 logger_server_dispatcher_client_thread(void* context)
1474 {
1475 output_stream los;
1476 input_stream lis;
1477 int *sockfdp = (int*)context;
1478 int sockfd = *sockfdp;
1479 ZFREE_OBJECT(sockfdp);
1480
1481 fd_input_stream_attach_noclose(&lis, sockfd);
1482 //buffer_input_stream_init(&lis, &lis, 4096);
1483 fd_output_stream_attach_noclose(&los, sockfd);
1484
1485 bool must_run = TRUE;
1486
1487 logger_message* message = logger_message_alloc();
1488
1489 while(must_run)
1490 {
1491 if(input_stream_read_u8(&lis, &message->type) == 0)
1492 {
1493 continue;
1494 }
1495
1496 switch(message->type)
1497 {
1498 case LOGGER_MESSAGE_TYPE_TEXT:
1499 {
1500 struct logger_message_text_s *logger_message_text = (struct logger_message_text_s*)message;
1501 input_stream_read(&lis, &logger_message_text->level, offsetof(struct logger_message_text_s, text) - 1);
1502 input_stream_read(&lis, &logger_message_text->tv, sizeof(struct logger_message_text_s) - offsetof(struct logger_message_text_s, tv));
1503 u16 text_size = 0;
1504 input_stream_read_u16(&lis, &text_size);
1505 ZALLOC_ARRAY_OR_DIE(u8*, logger_message_text->text, logger_message_text->text_buffer_length, BYTE_ARRAY_OUTPUT_STREAM_BUFF_TAG);
1506 input_stream_read(&lis, logger_message_text->text, text_size);
1507 logger_message_post(message);
1508 message = logger_message_alloc();
1509 break;
1510 }
1511
1512 case LOGGER_MESSAGE_TYPE_STOP:
1513 {
1514 must_run = FALSE;
1515 /*
1516 must_run = threaded_queue_size(&logger_commit_queue) > 0;
1517 if(must_run)
1518 {
1519 // repost
1520 logger_message_post(message);
1521 message = logger_message_alloc();
1522 }
1523
1524 async_wait_progress(message->handle_close.aw, 1);
1525 */
1526
1527 break;
1528 }
1529 case LOGGER_MESSAGE_TYPE_CHANNEL_FLUSH_ALL:
1530 case LOGGER_MESSAGE_TYPE_CHANNEL_REOPEN_ALL:
1531 case LOGGER_MESSAGE_TYPE_CHANNEL_CLOSE_ALL:
1532 case LOGGER_MESSAGE_TYPE_CHANNEL_SINK_ALL:
1533 {
1534 #if HAS_SHARED_QUEUE_SUPPORT
1535 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
1536 message->channel_flush_all.aw = aw;
1537 #else
1538 async_wait_s aw;
1539 async_wait_init(&aw, 1);
1540 message->channel_flush_all.aw = &aw;
1541 #endif
1542 logger_message_post(message);
1543
1544 while(logger_initialised_and_started())
1545 {
1546 #if HAS_SHARED_QUEUE_SUPPORT
1547 if(async_wait_timeout(aw, ONE_SECOND_US))
1548 {
1549 async_wait_destroy_shared(aw);
1550 break;
1551 }
1552 #else
1553 if(async_wait_timeout(&aw, ONE_SECOND_US))
1554 {
1555 async_wait_finalize(&aw);
1556 break;
1557 }
1558 #endif
1559 }
1560
1561 message = logger_message_alloc();
1562
1563 output_stream_write_u8(&los, 1);
1564
1565 break;
1566 }
1567 default:
1568 {
1569 abort();
1570 }
1571 }
1572 }
1573
1574 logger_message_free(message);
1575 ipc_client_close(sockfd);
1576
1577 return NULL;
1578 }
1579
1580 static void*
logger_server_dispatcher_thread(void * context)1581 logger_server_dispatcher_thread(void* context)
1582 {
1583 #if DNSCORE_HAS_LOG_THREAD_TAG
1584 static char loggersr_thread_tag[9] = "loggersr";
1585 logger_handle_set_thread_tag(loggersr_thread_tag);
1586 #endif
1587 int sockfd = ipc_server_listen("logger");
1588 int ret;
1589
1590 for(;;)
1591 {
1592 int clientfd = ipc_server_accept(sockfd);
1593 if(clientfd >= 0)
1594 {
1595 int *clientfdp;
1596 ZALLOC_OBJECT_OR_DIE(clientfdp, int, GENERIC);
1597 *clientfdp = clientfd;
1598 if((ret = thread_create(&logger_thread_id, logger_server_dispatcher_client_thread, clientfdp)) != 0)
1599 {
1600 }
1601 }
1602 }
1603 ipc_server_close(sockfd);
1604
1605 return NULL;
1606 }
1607 #endif
1608
1609 static void*
logger_dispatcher_thread(void * context)1610 logger_dispatcher_thread(void* context)
1611 {
1612 (void)context;
1613
1614 #if DEBUG_LOG_HANDLER
1615 debug_osformatln(termout, "logger: dispatcher starting");
1616 flushout();
1617 #endif
1618
1619 if(!smp_int_setifequal(&logger_thread_state, LOGGER_DISPATCHED_THREAD_STOPPED, LOGGER_DISPATCHED_THREAD_STARTED))
1620 {
1621 debug_osformatln(termout, "logger_dispatcher_thread(%p) state expected to be LOGGER_DISPATCHED_THREAD_STOPPED", context);
1622 return NULL;
1623 }
1624
1625 #if DEBUG_LOG_HANDLER
1626 debug_osformatln(termout, "logger_dispatcher_thread(%p) started", context);
1627 flushout();
1628 #endif
1629
1630 thread_set_name("logger", 0U, 0);
1631
1632 #if DNSCORE_HAS_LOG_THREAD_TAG
1633 thread_set_tag_with_pid_and_tid(getpid_ex(), thread_self(), "logger");
1634 #endif
1635
1636 output_stream baos;
1637 bytearray_output_stream_context baos_context;
1638 bytearray_output_stream_init_ex_static(&baos, NULL, 1024, BYTEARRAY_DYNAMIC, &baos_context);
1639
1640 /*
1641 * Since I'll use this virtual call a lot, it's best to cache it.
1642 * (Actually it would be even better to use the static method)
1643 */
1644 output_stream_write_method *baos_write = baos.vtbl->write;
1645
1646 #if !HAS_SHARED_QUEUE_SUPPORT
1647 char repeat_text[128];
1648
1649 #if DNSCORE_HAS_LOG_THREAD_TAG
1650 char thread_tag_buffer[12];
1651 #endif
1652 #endif
1653
1654 if(!smp_int_setifequal(&logger_thread_state, LOGGER_DISPATCHED_THREAD_STARTED, LOGGER_DISPATCHED_THREAD_READY))
1655 {
1656 debug_osformatln(termout, "logger_dispatcher_thread(%p) state expected to be LOGGER_DISPATCHED_THREAD_STARTED", context);
1657 return NULL;
1658 }
1659
1660 bool must_run = TRUE;
1661
1662 while(must_run)
1663 {
1664 #if DEBUG_LOG_HANDLER > 1
1665 debug_osformatln(termout, "logger: waiting for message");
1666 flushout();
1667 #endif
1668
1669 #if HAS_SHARED_QUEUE_SUPPORT
1670 struct shared_circular_buffer_slot* slot = shared_circular_buffer_prepare_dequeue(logger_shared_queue);
1671 logger_message* message = (logger_message*)slot;
1672
1673 #else
1674 logger_message* message = (logger_message*)threaded_queue_dequeue(&logger_commit_queue);
1675 #endif
1676
1677 assert(message != NULL);
1678
1679 #if DEBUG_LOG_HANDLER
1680 #if DEBUG_LOG_HANDLER > 1
1681 debug_osformatln(termout, "logger: got message %p (%i) from %i:%p",
1682 message,
1683 message->type,
1684 message->pid,
1685 message->text.thread_id);
1686 flushout();
1687 #else
1688 if(logger_thread_pid != getpid_ex())
1689 {
1690 debug_osformatln(termout, "logger: got message %p (%i) from %i:%p",
1691 message,
1692 message->type,
1693 message->pid,
1694 message->text.thread_id);
1695 flushout();
1696 }
1697 #endif
1698 if(kill(message->pid, 0) < 0)
1699 {
1700 debug_osformatln(termerr, "logger: got message %p (%i) from %i:%p : PID doesn't exist",
1701 message,
1702 message->type,
1703 message->pid,
1704 message->text.thread_id);
1705 flusherr();
1706 }
1707 #endif
1708 /*
1709 * Reopen is not a message per se.
1710 * It has to be done "now" (ie: the disk is full, files have to be moved)
1711 * But if it was handled as a message, it would need to clear the queue before having an effect.
1712 * So instead a flag is used0
1713 */
1714
1715 {
1716 mutex_lock(&logger_mutex);
1717 logger_message *logger_sink_request_message = logger_shared_space->_logger_sink_request_message;
1718 if(logger_sink_request_message != NULL)
1719 {
1720 logger_shared_space->_logger_sink_request_message = NULL;
1721 }
1722 logger_message *logger_reopen_request_message = logger_shared_space->_logger_reopen_request_message;
1723 if(logger_reopen_request_message != NULL)
1724 {
1725 logger_shared_space->_logger_reopen_request_message = NULL;
1726 }
1727 mutex_unlock(&logger_mutex);
1728
1729 if(((intptr)logger_sink_request_message | (intptr)logger_reopen_request_message) != 0)
1730 {
1731 if(logger_sink_request_message != NULL)
1732 {
1733 logger_service_sink_all_channels();
1734
1735 if(logger_sink_request_message != LOGGER_MESSAGE_SINK_FAKE)
1736 {
1737 if(logger_sink_request_message->channel_sink_all.aw != NULL)
1738 {
1739
1740 async_wait_progress(logger_sink_request_message->channel_sink_all.aw, 1);
1741 }
1742 logger_sink_request_message->channel_sink_all.aw = NULL;
1743 }
1744 }
1745
1746 if(logger_reopen_request_message != NULL)
1747 {
1748 logger_service_reopen_all_channels();
1749 if(logger_reopen_request_message->channel_sink_all.aw != NULL)
1750 {
1751 async_wait_progress(logger_reopen_request_message->channel_reopen_all.aw, 1);
1752 logger_reopen_request_message->channel_reopen_all.aw = NULL;
1753 }
1754 }
1755 }
1756 }
1757
1758 switch(message->type)
1759 {
1760 case LOGGER_MESSAGE_TYPE_TEXT:
1761 {
1762 #if DEBUG_LOG_MESSAGES
1763 {
1764 time_t now = time(NULL);
1765 if(now - allocated_messages_count_stats_time > 10)
1766 {
1767 allocated_messages_count_stats_time = now;
1768 int val = smp_int_get(&allocated_messages_count);
1769
1770 //debug_osformatln(termerr, "messages allocated count = %d", val);
1771 //flusherr();
1772 osformat(&baos, "[LOGGER: %i messages allocated]\n", val);
1773 }
1774 }
1775 #endif
1776
1777 logger_handle *handle = message->text.handle;
1778 u32 level = message->text.level;
1779
1780 s32 channel_count = handle->channels[level].offset;
1781
1782 if(channel_count < 0)
1783 {
1784 #if HAS_SHARED_QUEUE_SUPPORT
1785 shared_heap_free(message->text.text);
1786 shared_circular_buffer_commit_dequeue(logger_shared_queue);
1787 #else
1788 ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
1789 logger_message_free(message);
1790 #endif
1791 continue;
1792 }
1793
1794 u32 date_header_len;
1795
1796 if(message->text.flags == 0)
1797 {
1798 struct tm t;
1799 #if SIZEOF_TIMEVAL <= 8
1800 localtime_r(&message->text.tv.tv_sec, &t);
1801 osformat(&baos, "%04d-%02d-%02d %02d:%02d:%02d.%06d",
1802 t.tm_year + 1900U, t.tm_mon + 1, t.tm_mday,
1803 t.tm_hour, t.tm_min, t.tm_sec, message->text.tv.tv_usec);
1804 #else
1805 time_t tv_sec = message->text.timestamp / ONE_SECOND_US;
1806 localtime_r(&tv_sec, &t);
1807 osformat(&baos, "%04d-%02d-%02d %02d:%02d:%02d.%06d",
1808 t.tm_year + 1900U, t.tm_mon + 1, t.tm_mday,
1809 t.tm_hour, t.tm_min, t.tm_sec, message->text.timestamp % ONE_SECOND_US);
1810 #endif
1811
1812
1813
1814 baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1815
1816 #if HAS_SHARED_QUEUE_SUPPORT
1817 format_dec_u64(message->pid, &baos, 6, ' ', FALSE);
1818 baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1819 #else
1820 #if DEBUG || HAS_LOG_PID
1821 format_dec_u64(message->text.pid, &baos, 6, ' ', FALSE);
1822 baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1823 #endif
1824 #endif
1825 #if DEBUG || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
1826 #if DNSCORE_HAS_LOG_THREAD_TAG
1827 baos_write(&baos, (const u8*)thread_get_tag_with_pid_and_tid(message->pid, message->text.thread_id), 8);
1828 #else
1829 osprint_u32_hex(&baos, (u32)message->text.thread_id);
1830 #endif
1831 baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1832 #endif
1833
1834 baos_write(&baos, (u8*)handle->formatted_name, LOGGER_HANDLE_FORMATTED_NAME_SIZE_MAX);
1835 baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1836
1837 osprint_char(&baos, acewnid[message->text.level & 15]);
1838 baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1839
1840 date_header_len = 29;
1841 }
1842 else
1843 {
1844 /* shortcut : assume both ones on since that's the only used case */
1845
1846 assert( (message->text.flags & (LOGGER_MESSAGE_TIMEMS | LOGGER_MESSAGE_PREFIX)) == (LOGGER_MESSAGE_TIMEMS | LOGGER_MESSAGE_PREFIX));
1847
1848 struct tm t;
1849 #if SIZEOF_TIMEVAL <= 8
1850 localtime_r(&message->text.tv.tv_sec, &t);
1851 osformat(&baos, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
1852 t.tm_year + 1900U, t.tm_mon + 1, t.tm_mday,
1853 t.tm_hour, t.tm_min, t.tm_sec, message->text.tv.tv_usec / 1000);
1854 baos_write(&baos, message->text.prefix, message->text.prefix_length);
1855 #else
1856 time_t tv_sec = message->text.timestamp / ONE_SECOND_US;
1857 localtime_r(&tv_sec, &t);
1858 osformat(&baos, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
1859 t.tm_year + 1900U, t.tm_mon + 1, t.tm_mday,
1860 t.tm_hour, t.tm_min, t.tm_sec, (message->text.timestamp % ONE_SECOND_US) / 1000ULL);
1861 baos_write(&baos, message->text.prefix, message->text.prefix_length);
1862 #endif
1863
1864
1865 date_header_len = 24;
1866 }
1867
1868 baos_write(&baos, message->text.text, message->text.text_length);
1869
1870 #if HAS_SHARED_QUEUE_SUPPORT
1871 shared_heap_free(message->text.text);
1872 shared_circular_buffer_commit_dequeue(logger_shared_queue);
1873 #endif
1874
1875 output_stream_write_u8(&baos, 0);
1876
1877 size_t size = bytearray_output_stream_size(&baos) - 1;
1878 char* buffer = (char*)bytearray_output_stream_buffer(&baos);
1879
1880 logger_channel** channelp = (logger_channel**)handle->channels[level].data;
1881
1882 do
1883 {
1884 logger_channel* channel = *channelp;
1885
1886 ya_result return_code;
1887
1888 #if !HAS_SHARED_QUEUE_SUPPORT
1889 if((channel->last_message->text.text_length == message->text.text_length) && (memcmp(channel->last_message->text.text, message->text.text, message->text.text_length) == 0))
1890 {
1891 /* match, it's a repeat */
1892 channel->last_message_count++;
1893 }
1894 else
1895 {
1896 /* no match */
1897
1898 if(channel->last_message_count > 0)
1899 {
1900 /* log the repeat count */
1901
1902 /* If the same line is outputted twice : filter it to say 'repeated' instead of sending everything */
1903
1904 struct tm t;
1905 #if SIZE_TIMEVAL <= 8
1906 localtime_r(&message->text.tv.tv_sec, &t);
1907 #else
1908 localtime_r(&message->text.timestamp / 1000000ULL, &t);
1909 #endif
1910
1911 #if 1
1912 #if DNSCORE_HAS_LOG_THREAD_TAG
1913 thread_copy_tag(channel->last_message->text.thread_id, thread_tag_buffer);
1914 #endif
1915
1916 return_code = snformat(repeat_text, sizeof(repeat_text),
1917
1918 #if (DEBUG || HAS_LOG_PID) && DNSCORE_HAS_LOG_THREAD_TAG
1919 "%04d-%02d-%02d %02d:%02d:%02d.%06d | %-5i | %s | -------- | N | last message repeated %d times",
1920 #elif DEBUG || (HAS_LOG_PID && HAS_LOG_THREAD_ID)
1921 "%04d-%02d-%02d %02d:%02d:%02d.%06d | %-5i | %08x | -------- | N | last message repeated %d times",
1922 #elif DNSCORE_HAS_LOG_THREAD_TAG
1923 "%04d-%02d-%02d %02d:%02d:%02d.%06d | %s | -------- | N | last message repeated %d times",
1924 #elif HAS_LOG_THREAD_ID
1925 "%04d-%02d-%02d %02d:%02d:%02d.%06d | %08x | -------- | N | last message repeated %d times",
1926 #elif HAS_LOG_PID
1927 "%04d-%02d-%02d %02d:%02d:%02d.%06d | %-5i | -------- | N | last message repeated %d times",
1928 #else
1929 "%04d-%02d-%02d %02d:%02d:%02d.%06d | -------- | N | last message repeated %d times",
1930 #endif
1931 t.tm_year + 1900U, t.tm_mon + 1, t.tm_mday,
1932 t.tm_hour, t.tm_min, t.tm_sec,
1933 #if SIZE_TIMEVAL <= 8
1934 message->text.tv.tv_usec
1935 #else
1936 message->text.timestamp % ONE_SECOND_US
1937 #endif
1938 ,
1939 #if DEBUG || HAS_LOG_PID
1940 getpid_ex(),
1941 #endif
1942 #if DNSCORE_HAS_LOG_THREAD_TAG
1943 thread_tag_buffer,
1944 #else
1945 #if DEBUG || HAS_LOG_THREAD_ID
1946 channel->last_message->text.thread_id,
1947 #endif
1948 #endif
1949 channel->last_message_count);
1950 #else
1951
1952 return_code = snformat(repeat_text, sizeof(repeat_text), "%04d-%02d-%02d %02d:%02d:%02d.%06d" COLUMN_SEPARATOR
1953 #if DEBUG
1954 "%-5d" COLUMN_SEPARATOR
1955 "%08x" COLUMN_SEPARATOR
1956 #endif
1957 "--------" COLUMN_SEPARATOR
1958 "N" COLUMN_SEPARATOR
1959 "last message repeated %d times",
1960 t.tm_year + 1900U, t.tm_mon + 1, t.tm_mday,
1961 t.tm_hour, t.tm_min, t.tm_sec,
1962 #if SIZE_TIMEVAL <= 8
1963 message->text.tv.tv_usec
1964 #else
1965 message->text.timestamp % ONE_SECOND_US
1966 #endif
1967 ,
1968 #if DEBUG || HAS_LOG_PID
1969 channel->last_message->text.pid,
1970 #endif
1971 #if DEBUG || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
1972 channel->last_message->text.thread_id,
1973 #endif
1974 channel->last_message_count);
1975 #endif
1976
1977
1978 if(ISOK(return_code))
1979 {
1980 while(FAIL(return_code = logger_channel_msg(channel, level, repeat_text, return_code, 29)))
1981 {
1982 if(stdstream_is_tty(termerr))
1983 {
1984 debug_osformatln(termerr, "message write failed on channel: %r", return_code);
1985 flusherr();
1986 }
1987
1988 if(return_code == MAKE_ERRNO_ERROR(EBADF) || return_code == MAKE_ERRNO_ERROR(ENOSPC))
1989 {
1990 logger_sink_requested = TRUE;
1991 }
1992
1993 if(logger_sink_requested || logger_reopen_requested)
1994 {
1995 if(logger_sink_requested)
1996 {
1997 logger_service_sink_all_channels();
1998 logger_sink_requested = FALSE;
1999 }
2000 if(logger_reopen_requested)
2001 {
2002 logger_service_reopen_all_channels();
2003 logger_reopen_requested = FALSE;
2004 }
2005 }
2006
2007 if(dnscore_shuttingdown())
2008 {
2009 // message will be lost
2010 break;
2011 }
2012
2013 sleep(1);
2014 }
2015 }
2016 else
2017 {
2018 if(stdstream_is_tty(termerr))
2019 {
2020 debug_osformatln(termerr, "message formatting failed on channel: %r", return_code);
2021 flusherr();
2022 }
2023 }
2024 }
2025
2026 /* cleanup */
2027 if(--channel->last_message->text.rc == 0)
2028 {
2029 /* free the message */
2030
2031 #if DEBUG_LOG_MESSAGES
2032 debug_osformatln(termout, "message rc is 0 (%s)", channel->last_message->text.text);
2033 flushout();
2034 #endif
2035 ZFREE_ARRAY(channel->last_message->text.text, channel->last_message->text.text_buffer_length);
2036 logger_message_free(channel->last_message);
2037 }
2038 #if DEBUG_LOG_MESSAGES
2039 else
2040 {
2041 debug_osformatln(termout, "message rc decreased to %d (%s)", channel->last_message->text.rc, channel->last_message->text.text);
2042 flushout();
2043 }
2044
2045 channel->last_message = message;
2046 channel->last_message_count = 0;
2047 message->text.rc++;
2048 #endif
2049
2050
2051 #if DEBUG_LOG_MESSAGES
2052 debug_osformatln(termout, "message rc is %d (%s)", channel->last_message->text.rc, channel->last_message->text.text);
2053 flushout();
2054 #endif
2055
2056 #endif // !HAS_SHARED_QUEUE_SUPPORT (no repeat compression)
2057
2058 while(FAIL(return_code = logger_channel_msg(channel, level, buffer, size, date_header_len)))
2059 {
2060 if(stdstream_is_tty(termerr))
2061 {
2062 debug_osformatln(termerr, "message write failed on channel: %r", return_code);
2063 flusherr();
2064 }
2065
2066 bool logger_sink_requested = FALSE;
2067
2068 if((return_code == MAKE_ERRNO_ERROR(EBADF)) || (return_code == MAKE_ERRNO_ERROR(ENOSPC)))
2069 {
2070 logger_sink_requested = TRUE;
2071 }
2072
2073 mutex_lock(&logger_mutex);
2074 logger_message *logger_sink_request_message = logger_shared_space->_logger_sink_request_message;
2075 if(logger_sink_request_message != NULL)
2076 {
2077 logger_shared_space->_logger_sink_request_message = NULL;
2078 }
2079 logger_message *logger_reopen_request_message = logger_shared_space->_logger_reopen_request_message;
2080 if(logger_reopen_request_message != NULL)
2081 {
2082 logger_shared_space->_logger_reopen_request_message = NULL;
2083 }
2084 mutex_unlock(&logger_mutex);
2085
2086 if(logger_sink_request_message != NULL)
2087 {
2088 logger_service_sink_all_channels();
2089 //logger_sink_requested = FALSE;
2090 if(logger_sink_request_message != LOGGER_MESSAGE_SINK_FAKE)
2091 {
2092 if(logger_sink_request_message->channel_sink_all.aw != NULL)
2093 {
2094
2095 async_wait_progress(logger_sink_request_message->channel_sink_all.aw, 1);
2096 }
2097 logger_sink_request_message->channel_sink_all.aw = NULL;
2098 }
2099 }
2100 else if(logger_sink_requested)
2101 {
2102 logger_service_sink_all_channels();
2103 //logger_sink_requested = FALSE;
2104 }
2105
2106 if(logger_reopen_request_message != NULL)
2107 {
2108 logger_service_reopen_all_channels();
2109 if(logger_reopen_request_message->channel_sink_all.aw != NULL)
2110 {
2111 async_wait_progress(logger_reopen_request_message->channel_reopen_all.aw, 1);
2112 logger_reopen_request_message->channel_reopen_all.aw = NULL;
2113 }
2114 }
2115
2116 if(dnscore_shuttingdown())
2117 {
2118 // message will be lost
2119 break;
2120 }
2121
2122 sleep(1);
2123 }
2124 #if !HAS_SHARED_QUEUE_SUPPORT
2125 }
2126 #endif
2127
2128 channelp++;
2129 }
2130 while(--channel_count >= 0);
2131
2132 #if !HAS_SHARED_QUEUE_SUPPORT
2133 if(message->text.rc == 0)
2134 {
2135 #if DEBUG_LOG_HANDLER
2136 debug_osformatln(termout, "message has not been used (full dup): '%s'", message->text.text);
2137 flushout();
2138 #endif
2139 ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
2140 logger_message_free(message);
2141 }
2142 #endif
2143 bytearray_output_stream_reset(&baos);
2144
2145 break;
2146 }
2147
2148 case LOGGER_MESSAGE_TYPE_CHANNEL_CLOSE_ALL:
2149 {
2150 async_wait_s *awp = message->channel_flush_all.aw;
2151
2152 #if HAS_SHARED_QUEUE_SUPPORT
2153 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2154 #else
2155 logger_message_free(message);
2156 #endif
2157
2158 logger_service_flush_all_channels();
2159 //logger_service_close_all_channels();
2160 logger_service_channel_unregister_all();
2161
2162 async_wait_progress(awp, 1);
2163
2164 break;
2165 }
2166
2167 case LOGGER_MESSAGE_TYPE_STOP:
2168 {
2169 #if HAS_SHARED_QUEUE_SUPPORT
2170 must_run = shared_circular_buffer_size(logger_shared_queue) > 1;
2171 if(must_run)
2172 {
2173 // repost
2174 logger_message* new_message = (logger_message*)shared_circular_buffer_prepare_enqueue(logger_shared_queue);
2175 #if HAS_SHARED_QUEUE_SUPPORT
2176 new_message->pid = getpid_ex();
2177 #endif
2178 new_message->type = LOGGER_MESSAGE_TYPE_STOP;
2179 new_message->stop.aw = message->stop.aw;
2180 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2181 shared_circular_buffer_commit_enqueue(logger_shared_queue, (struct shared_circular_buffer_slot*)new_message);
2182 }
2183 else
2184 {
2185 async_wait_s *awp = message->handle_close.aw;
2186 shared_circular_buffer_commit_dequeue(logger_shared_queue); // destroys the message but not the synchronisation structure.
2187 async_wait_progress(awp, 1);
2188 }
2189 #else
2190 must_run = threaded_queue_size(&logger_commit_queue) > 0;
2191 if(must_run)
2192 {
2193 // repost
2194 logger_message_post(message);
2195 }
2196 else
2197 {
2198 async_wait_s *awp = message->handle_close.aw;
2199 async_wait_progress(awp, 1);
2200 }
2201 #endif
2202 break;
2203 }
2204
2205 /// @note fall through by design
2206
2207 case LOGGER_MESSAGE_TYPE_CHANNEL_FLUSH_ALL:
2208 {
2209 async_wait_s *awp = message->channel_flush_all.aw;
2210
2211 #if HAS_SHARED_QUEUE_SUPPORT
2212 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2213 #else
2214 logger_message_free(message);
2215 #endif
2216
2217 logger_service_flush_all_channels();
2218
2219 async_wait_progress(awp, 1);
2220
2221 break;
2222 }
2223
2224 case LOGGER_MESSAGE_TYPE_CHANNEL_REOPEN_ALL:
2225 {
2226 // reopen is activated by a flag
2227 // this structure is just a way to fire the event
2228
2229 async_wait_s *awp = message->channel_reopen_all.aw;
2230 if(awp != NULL)
2231 {
2232 if(stdstream_is_tty(termerr))
2233 {
2234 debug_osformatln(termerr, "logger: unexpected synchronization point in reopen");
2235 flusherr();
2236 }
2237
2238 async_wait_progress(awp, 1);
2239 }
2240 #if HAS_SHARED_QUEUE_SUPPORT
2241 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2242 #else
2243 logger_message_free(message);
2244 #endif
2245 break;
2246 }
2247
2248 case LOGGER_MESSAGE_TYPE_CHANNEL_SINK_ALL:
2249 {
2250 // sink is activated by a flag
2251 // this structure is just a way to fire the event
2252
2253 async_wait_s *awp = message->channel_sink_all.aw;
2254 if(awp != NULL)
2255 {
2256 if(stdstream_is_tty(termerr))
2257 {
2258 debug_osformatln(termerr, "logger: unexpected synchronization point in sink");
2259 flusherr();
2260 }
2261
2262 async_wait_progress(awp, 1);
2263 }
2264
2265 #if HAS_SHARED_QUEUE_SUPPORT
2266 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2267 #else
2268 logger_message_free(message);
2269 #endif
2270 break;
2271 }
2272
2273 case LOGGER_MESSAGE_TYPE_IGNORE:
2274 {
2275 #if HAS_SHARED_QUEUE_SUPPORT
2276 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2277 #else
2278 logger_message_free(message);
2279 #endif
2280 break;
2281 }
2282
2283 case LOGGER_MESSAGE_TYPE_CHANNEL_GET_USAGE_COUNT:
2284 {
2285 async_wait_s *awp = message->get_usage_count.aw;
2286 const char *channel_name = message->get_usage_count.channel_name;
2287
2288 s32 *countp = message->get_usage_count.countp;
2289
2290 assert(countp != NULL);
2291
2292 #if HAS_SHARED_QUEUE_SUPPORT
2293 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2294 #else
2295 logger_message_free(message);
2296 #endif
2297
2298 logger_channel *channel = logger_service_channel_get(channel_name);
2299
2300 if(channel != NULL)
2301 {
2302 *countp = channel->linked_handles;
2303 }
2304 else
2305 {
2306 *countp = -1;
2307 }
2308
2309 async_wait_progress(awp, 1);
2310 break;
2311 }
2312
2313 case LOGGER_MESSAGE_TYPE_CHANNEL_REGISTER:
2314 {
2315 async_wait_s *awp = message->channel_register.aw;
2316 const char *channel_name = message->channel_register.channel_name;
2317 logger_channel *channel = message->channel_register.channel;
2318
2319 #if HAS_SHARED_QUEUE_SUPPORT
2320 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2321 #else
2322 logger_message_free(message);
2323 #endif
2324
2325 logger_service_channel_register(channel_name, channel);
2326
2327 async_wait_progress(awp, 1);
2328 break;
2329 }
2330
2331 case LOGGER_MESSAGE_TYPE_CHANNEL_UNREGISTER:
2332 {
2333 async_wait_s *awp = message->channel_unregister.aw;
2334 const char *channel_name = message->channel_unregister.channel_name;
2335
2336 #if HAS_SHARED_QUEUE_SUPPORT
2337 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2338 #else
2339 logger_message_free(message);
2340 #endif
2341
2342 logger_service_channel_unregister(channel_name);
2343
2344 async_wait_progress(awp, 1);
2345 break;
2346 }
2347
2348 case LOGGER_MESSAGE_TYPE_HANDLE_CREATE:
2349 {
2350 async_wait_s *awp = message->handle_create.aw;
2351 const char *name = message->handle_create.logger_name;
2352 logger_handle **handlep = message->handle_create.handle_holder;
2353 logger_handle* handle = logger_service_handle_create(name);
2354 handle->global_reference = handlep;
2355 *handlep = handle;
2356
2357 #if HAS_SHARED_QUEUE_SUPPORT
2358 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2359 #else
2360 logger_message_free(message);
2361 #endif
2362 async_wait_progress(awp, 1);
2363 break;
2364 }
2365
2366 case LOGGER_MESSAGE_TYPE_HANDLE_CLOSE:
2367 {
2368 async_wait_s *awp = message->handle_close.aw;
2369 const char *name = message->handle_close.logger_name;
2370 //u32 name_len = message->text_length;
2371 logger_service_handle_close(name);
2372
2373 #if HAS_SHARED_QUEUE_SUPPORT
2374 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2375 #else
2376 logger_message_free(message);
2377 #endif
2378
2379 async_wait_progress(awp, 1);
2380 break;
2381 }
2382
2383 case LOGGER_MESSAGE_TYPE_HANDLE_NAME_ADD_CHANNEL:
2384 {
2385 logger_handle *handle;
2386 async_wait_s *awp = message->handle_add_channel.aw;
2387 const char *name = message->handle_add_channel.logger_name;
2388 int level = message->handle_add_channel.level;
2389 const char *channel_name = message->handle_add_channel.channel_name;
2390
2391 handle = logger_service_handle_get(name);
2392 if(handle != NULL)
2393 {
2394 logger_service_handle_add_channel(handle, level, channel_name);
2395 }
2396
2397 #if HAS_SHARED_QUEUE_SUPPORT
2398 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2399 #else
2400 logger_message_free(message);
2401 #endif
2402
2403 async_wait_progress(awp, 1);
2404 break;
2405 }
2406
2407 case LOGGER_MESSAGE_TYPE_HANDLE_NAME_REMOVE_CHANNEL:
2408 {
2409 logger_handle *handle;
2410 async_wait_s *awp = message->handle_remove_channel.aw;
2411 const char *name = message->handle_remove_channel.logger_name;
2412 const char *channel_name = message->handle_remove_channel.channel_name;
2413
2414 handle = logger_service_handle_get(name);
2415 if(handle != NULL)
2416 {
2417 logger_service_handle_remove_channel(handle, channel_name);
2418 }
2419
2420 #if HAS_SHARED_QUEUE_SUPPORT
2421 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2422 #else
2423 logger_message_free(message);
2424 #endif
2425
2426 async_wait_progress(awp, 1);
2427 break;
2428 }
2429
2430 case LOGGER_MESSAGE_TYPE_HANDLE_NAME_COUNT_CHANNELS:
2431 {
2432 logger_handle *handle;
2433 async_wait_s *awp = message->handle_count_channels.aw;
2434 const char *name = message->handle_count_channels.logger_name;
2435
2436 handle = logger_service_handle_get(name);
2437
2438 *message->handle_count_channels.countp = 0;
2439
2440 if(handle != NULL)
2441 {
2442 *message->handle_count_channels.countp = logger_service_handle_count_channels(handle);
2443 }
2444
2445 #if HAS_SHARED_QUEUE_SUPPORT
2446 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2447 #else
2448 logger_message_free(message);
2449 #endif
2450
2451 async_wait_progress(awp, 1);
2452 break;
2453 }
2454 #if DNSCORE_HAS_LOG_THREAD_TAG
2455 case LOGGER_MESSAGE_TYPE_THREAD_SET_TAG:
2456 {
2457 async_wait_s *awp = message->thread_set_tag.aw;
2458 #if DEBUG
2459 #if DEBUG_LOG_REGISTRATIONS
2460 printf("logger: registering: pid=%i thread=%p tag=%c%c%c%c%c%c%c%c (printf)\n",
2461 message->pid, (void*)(intptr_t)message->thread_set_tag.tid,
2462 message->thread_set_tag.tag[0],message->thread_set_tag.tag[1],message->thread_set_tag.tag[2],message->thread_set_tag.tag[3],
2463 message->thread_set_tag.tag[4],message->thread_set_tag.tag[5],message->thread_set_tag.tag[6],message->thread_set_tag.tag[7]);
2464 debug_osformatln(termout, "logger: registering: pid=%i thread=%p tag=%c%c%c%c%c%c%c%c (printf)",
2465 message->pid, (void*)(intptr_t)message->thread_set_tag.tid,
2466 message->thread_set_tag.tag[0],message->thread_set_tag.tag[1],message->thread_set_tag.tag[2],message->thread_set_tag.tag[3],
2467 message->thread_set_tag.tag[4],message->thread_set_tag.tag[5],message->thread_set_tag.tag[6],message->thread_set_tag.tag[7]);
2468 #endif
2469 #endif
2470 #if DEBUG
2471 #if DEBUG_LOG_REGISTRATIONS
2472 log_try_debug("logger: registering: pid=%i thread=%p tag=%c%c%c%c%c%c%c%c (log_try_debug)",
2473 message->pid, message->thread_set_tag.tid,
2474 message->thread_set_tag.tag[0],message->thread_set_tag.tag[1],message->thread_set_tag.tag[2],message->thread_set_tag.tag[3],
2475 message->thread_set_tag.tag[4],message->thread_set_tag.tag[5],message->thread_set_tag.tag[6],message->thread_set_tag.tag[7]);
2476 #endif
2477 #endif
2478 thread_set_tag_with_pid_and_tid(message->pid, message->thread_set_tag.tid, message->thread_set_tag.tag);
2479
2480 #if HAS_SHARED_QUEUE_SUPPORT
2481 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2482 #else
2483 logger_message_free(message);
2484 #endif
2485 async_wait_progress(awp, 1);
2486 break;
2487 }
2488
2489 case LOGGER_MESSAGE_TYPE_THREAD_CLEAR_TAG:
2490 {
2491 async_wait_s *awp = message->thread_clear_tag.aw;
2492
2493 thread_clear_tag_with_pid_and_tid(message->pid, message->thread_clear_tag.tid);
2494
2495 #if HAS_SHARED_QUEUE_SUPPORT
2496 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2497 #else
2498 logger_message_free(message);
2499 #endif
2500 async_wait_progress(awp, 1);
2501 break;
2502 }
2503 #endif
2504 default:
2505 {
2506 if(stdstream_is_tty(termerr))
2507 {
2508 debug_osformatln(termerr, "unexpected message type %u in log queue", message->type);
2509 flusherr();
2510 }
2511
2512 break;
2513 }
2514 }
2515 } // while must run
2516
2517 if(!smp_int_setifequal(&logger_thread_state, LOGGER_DISPATCHED_THREAD_READY, LOGGER_DISPATCHED_THREAD_STOPPING))
2518 {
2519 debug_osformatln(termout, "logger_dispatcher_thread(%p) state expected to be LOGGER_DISPATCHED_THREAD_READY", context);
2520 return NULL;
2521 }
2522
2523 // flush everything
2524
2525 logger_service_flush_all_channels();
2526
2527 // close everything
2528
2529 output_stream_close(&baos);
2530
2531 #if DEBUG_LOG_HANDLER
2532 debug_osformatln(termout, "logger_dispatcher_thread(%p) END", context);
2533 flushout();
2534 #endif
2535
2536 #if DNSCORE_HAS_LOG_THREAD_TAG
2537 thread_clear_tag_with_pid_and_tid(getpid_ex(), thread_self());
2538 #endif
2539
2540 if(!smp_int_setifequal(&logger_thread_state, LOGGER_DISPATCHED_THREAD_STOPPING, LOGGER_DISPATCHED_THREAD_STOPPED))
2541 {
2542 debug_osformatln(termout, "logger_dispatcher_thread(%p) state expected to be LOGGER_DISPATCHED_THREAD_STOPPING", context);
2543 //return NULL;
2544 }
2545
2546 return NULL;
2547 }
2548
2549 s32
logger_channel_get_usage_count(const char * channel_name)2550 logger_channel_get_usage_count(const char* channel_name)
2551 {
2552 #if DEBUG_LOG_HANDLER
2553 debug_osformatln(termout, "logger_channel_get_usage_count(%s) ", channel_name);
2554 flushout();
2555 #endif
2556
2557 s32 count = -2;
2558
2559 if(logger_is_running())
2560 {
2561 logger_message *message = logger_message_alloc();
2562
2563 // ZEROMEMORY(message, sizeof(logger_message));
2564
2565 #if HAS_SHARED_QUEUE_SUPPORT
2566 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2567 #else
2568 async_wait_s aw;
2569 async_wait_init(&aw, 1);
2570 #endif
2571 #if HAS_SHARED_QUEUE_SUPPORT
2572 message->pid = getpid_ex();
2573 #endif
2574 message->type = LOGGER_MESSAGE_TYPE_CHANNEL_GET_USAGE_COUNT;
2575 #if HAS_SHARED_QUEUE_SUPPORT
2576 message->get_usage_count.aw = aw;
2577 #else
2578 message->get_usage_count.aw = &aw;
2579 #endif
2580 message->get_usage_count.channel_name = channel_name;
2581 message->get_usage_count.countp = &count;
2582
2583 logger_message_post(message);
2584
2585 #if HAS_SHARED_QUEUE_SUPPORT
2586 async_wait(aw);
2587 async_wait_destroy_shared(aw);
2588 #else
2589 async_wait(&aw);
2590 async_wait_finalize(&aw);
2591 #endif
2592 }
2593 else
2594 {
2595 #if HAS_SHARED_QUEUE_SUPPORT
2596 shared_circular_buffer_lock(logger_shared_queue);
2597 #else
2598 mutex_lock(&logger_commit_queue.mutex);
2599 #endif
2600
2601 logger_channel *channel = logger_service_channel_get(channel_name);
2602
2603 if(channel != NULL)
2604 {
2605 count = channel->linked_handles;
2606 }
2607 else
2608 {
2609 count = -1;
2610 }
2611
2612 #if HAS_SHARED_QUEUE_SUPPORT
2613 shared_circular_buffer_unlock(logger_shared_queue);
2614 #else
2615 mutex_unlock(&logger_commit_queue.mutex);
2616 #endif
2617 }
2618
2619 return count;
2620 }
2621
2622 void
logger_channel_register(const char * channel_name,struct logger_channel * channel)2623 logger_channel_register(const char* channel_name, struct logger_channel *channel)
2624 {
2625 if((channel == NULL) || (channel->vtbl == NULL))
2626 {
2627 debug_osformatln(termerr, "tried to register channel on uninitialised channel");
2628 return;
2629 }
2630
2631 #if DEBUG_LOG_HANDLER
2632 debug_osformatln(termout, "logger_channel_register(%s,%p) ", channel_name, channel);
2633 flushout();
2634 #endif
2635 if(logger_is_running())
2636 {
2637 logger_message *message = logger_message_alloc();
2638
2639 #if HAS_SHARED_QUEUE_SUPPORT
2640 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2641 #else
2642 async_wait_s aw;
2643 async_wait_init(&aw, 1);
2644 #endif
2645 #if HAS_SHARED_QUEUE_SUPPORT
2646 message->pid = getpid_ex();
2647 #endif
2648 message->type = LOGGER_MESSAGE_TYPE_CHANNEL_REGISTER;
2649 #if HAS_SHARED_QUEUE_SUPPORT
2650 message->channel_register.aw = aw;
2651 #else
2652 message->channel_register.aw = &aw;
2653 #endif
2654 message->channel_register.channel_name = channel_name;
2655 message->channel_register.channel = channel;
2656
2657 logger_message_post(message);
2658
2659 #if HAS_SHARED_QUEUE_SUPPORT
2660 async_wait(aw);
2661 async_wait_destroy_shared(aw);
2662 #else
2663 async_wait(&aw);
2664 async_wait_finalize(&aw);
2665 #endif
2666 }
2667 else
2668 {
2669 #if HAS_SHARED_QUEUE_SUPPORT
2670 shared_circular_buffer_lock(logger_shared_queue);
2671 #else
2672 mutex_lock(&logger_commit_queue.mutex);
2673 #endif
2674 logger_service_channel_register(channel_name, channel);
2675
2676 #if HAS_SHARED_QUEUE_SUPPORT
2677 shared_circular_buffer_unlock(logger_shared_queue);
2678 #else
2679 mutex_unlock(&logger_commit_queue.mutex);
2680 #endif
2681 }
2682 }
2683
2684 void
logger_channel_unregister(const char * channel_name)2685 logger_channel_unregister(const char* channel_name)
2686 {
2687 #if DEBUG_LOG_HANDLER
2688 debug_osformatln(termout, "logger_channel_unregister(%s) ", channel_name);
2689 flushout();
2690 #endif
2691
2692 logger_message *message = logger_message_alloc();
2693
2694 #if HAS_SHARED_QUEUE_SUPPORT
2695 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2696 #else
2697 async_wait_s aw;
2698 async_wait_init(&aw, 1);
2699 #endif
2700 #if HAS_SHARED_QUEUE_SUPPORT
2701 message->pid = getpid_ex();
2702 #endif
2703 message->type = LOGGER_MESSAGE_TYPE_CHANNEL_UNREGISTER;
2704
2705 #if HAS_SHARED_QUEUE_SUPPORT
2706 message->channel_unregister.aw = aw;
2707 #else
2708 message->channel_unregister.aw = &aw;
2709 #endif
2710 message->channel_unregister.channel_name = channel_name;
2711
2712 logger_message_post(message);
2713
2714 #if HAS_SHARED_QUEUE_SUPPORT
2715 async_wait(aw);
2716 async_wait_destroy_shared(aw);
2717 #else
2718 async_wait(&aw);
2719 async_wait_finalize(&aw);
2720 #endif
2721 }
2722
2723 void
logger_handle_create(const char * logger_name,logger_handle ** handle_holder)2724 logger_handle_create(const char *logger_name, logger_handle **handle_holder)
2725 {
2726 #if DEBUG_LOG_HANDLER
2727 debug_osformatln(termout, "logger_handle_create(%s,%p) ", logger_name, handle_holder);
2728 flushout();
2729 #endif
2730
2731 if(logger_is_running())
2732 {
2733 logger_message *message = logger_message_alloc();
2734
2735 #if HAS_SHARED_QUEUE_SUPPORT
2736 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2737 #else
2738 async_wait_s aw;
2739 async_wait_init(&aw, 1);
2740 #endif
2741 #if HAS_SHARED_QUEUE_SUPPORT
2742 message->pid = getpid_ex();
2743 #endif
2744 message->type = LOGGER_MESSAGE_TYPE_HANDLE_CREATE;
2745 #if HAS_SHARED_QUEUE_SUPPORT
2746 message->handle_create.aw = aw;
2747 #else
2748 message->handle_create.aw = &aw;
2749 #endif
2750 message->handle_create.logger_name = logger_name;
2751 message->handle_create.handle_holder = handle_holder;
2752
2753 logger_message_post(message);
2754
2755 #if HAS_SHARED_QUEUE_SUPPORT
2756 async_wait(aw);
2757 async_wait_destroy_shared(aw);
2758 #else
2759 async_wait(&aw);
2760 async_wait_finalize(&aw);
2761 #endif
2762 }
2763 else
2764 {
2765 #if HAS_SHARED_QUEUE_SUPPORT
2766 shared_circular_buffer_lock(logger_shared_queue);
2767 #else
2768 mutex_lock(&logger_commit_queue.mutex);
2769 #endif
2770 logger_handle* handle = logger_service_handle_create(logger_name);
2771 handle->global_reference = handle_holder;
2772 *handle_holder = handle;
2773
2774 #if HAS_SHARED_QUEUE_SUPPORT
2775 shared_circular_buffer_unlock(logger_shared_queue);
2776 #else
2777 mutex_unlock(&logger_commit_queue.mutex);
2778 #endif
2779 }
2780 }
2781
2782 void
logger_handle_close(const char * logger_name)2783 logger_handle_close(const char *logger_name)
2784 {
2785 #if DEBUG_LOG_HANDLER
2786 debug_osformatln(termout, "logger_handle_close(%s) ", logger_name);
2787 flushout();
2788 #endif
2789
2790 logger_message *message = logger_message_alloc();
2791
2792 #if HAS_SHARED_QUEUE_SUPPORT
2793 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2794 #else
2795 async_wait_s aw;
2796 async_wait_init(&aw, 1);
2797 #endif
2798 #if HAS_SHARED_QUEUE_SUPPORT
2799 message->pid = getpid_ex();
2800 #endif
2801 message->type = LOGGER_MESSAGE_TYPE_HANDLE_CLOSE;
2802 #if HAS_SHARED_QUEUE_SUPPORT
2803 message->handle_close.aw = aw;
2804 #else
2805 message->handle_close.aw = &aw;
2806 #endif
2807 message->handle_close.logger_name = logger_name;
2808
2809 logger_message_post(message);
2810
2811 #if HAS_SHARED_QUEUE_SUPPORT
2812 async_wait(aw);
2813 async_wait_destroy_shared(aw);
2814 #else
2815 async_wait(&aw);
2816 async_wait_finalize(&aw);
2817 #endif
2818 }
2819
2820 void
logger_handle_add_channel(const char * logger_name,int level,const char * channel_name)2821 logger_handle_add_channel(const char *logger_name, int level, const char *channel_name)
2822 {
2823 #if DEBUG_LOG_HANDLER
2824 debug_osformatln(termout, "logger_handle_add_channel(%s,%x,%s) ", logger_name, level, channel_name);
2825 flushout();
2826 #endif
2827
2828 if(logger_is_running())
2829 {
2830 logger_message *message = logger_message_alloc();
2831 ZEROMEMORY(message, sizeof(logger_message));
2832 #if HAS_SHARED_QUEUE_SUPPORT
2833 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2834 #else
2835 async_wait_s aw;
2836 async_wait_init(&aw, 1);
2837 #endif
2838 #if HAS_SHARED_QUEUE_SUPPORT
2839 message->pid = getpid_ex();
2840 #endif
2841 message->type = LOGGER_MESSAGE_TYPE_HANDLE_NAME_ADD_CHANNEL;
2842 #if HAS_SHARED_QUEUE_SUPPORT
2843 message->handle_add_channel.aw = aw;
2844 #else
2845 message->handle_add_channel.aw = &aw;
2846 #endif
2847 message->handle_add_channel.logger_name = logger_name;
2848 message->handle_add_channel.level = level;
2849 message->handle_add_channel.channel_name = channel_name;
2850
2851 logger_message_post(message);
2852
2853 #if HAS_SHARED_QUEUE_SUPPORT
2854 async_wait(aw);
2855 async_wait_destroy_shared(aw);
2856 #else
2857 async_wait(&aw);
2858 async_wait_finalize(&aw);
2859 #endif
2860 }
2861 else
2862 {
2863 #if HAS_SHARED_QUEUE_SUPPORT
2864 shared_circular_buffer_lock(logger_shared_queue);
2865 #else
2866 mutex_lock(&logger_commit_queue.mutex);
2867 #endif
2868 logger_handle *handle = logger_service_handle_get(logger_name);
2869 if(handle != NULL)
2870 {
2871 logger_service_handle_add_channel(handle, level, channel_name);
2872 }
2873
2874 #if HAS_SHARED_QUEUE_SUPPORT
2875 shared_circular_buffer_unlock(logger_shared_queue);
2876 #else
2877 mutex_unlock(&logger_commit_queue.mutex);
2878 #endif
2879 }
2880 }
2881
2882 void
logger_handle_remove_channel(const char * logger_name,const char * channel_name)2883 logger_handle_remove_channel(const char *logger_name, const char *channel_name)
2884 {
2885 #if DEBUG_LOG_HANDLER
2886 debug_osformatln(termout, "logger_handle_remove_channel(%s,%s) ", logger_name, channel_name);
2887 flushout();
2888 #endif
2889
2890 logger_message *message = logger_message_alloc();
2891
2892 #if HAS_SHARED_QUEUE_SUPPORT
2893 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2894 #else
2895 async_wait_s aw;
2896 async_wait_init(&aw, 1);
2897 #endif
2898 #if HAS_SHARED_QUEUE_SUPPORT
2899 message->pid = getpid_ex();
2900 #endif
2901 message->type = LOGGER_MESSAGE_TYPE_HANDLE_NAME_REMOVE_CHANNEL;
2902
2903 #if HAS_SHARED_QUEUE_SUPPORT
2904 message->handle_remove_channel.aw = aw;
2905 #else
2906 message->handle_remove_channel.aw = &aw;
2907 #endif
2908
2909 message->handle_remove_channel.logger_name = logger_name;
2910 message->handle_remove_channel.channel_name = channel_name;
2911
2912 logger_message_post(message);
2913
2914 #if HAS_SHARED_QUEUE_SUPPORT
2915 async_wait(aw);
2916 async_wait_destroy_shared(aw);
2917 #else
2918 async_wait(&aw);
2919 async_wait_finalize(&aw);
2920 #endif
2921 }
2922
2923 /**
2924 *
2925 * Helper function.
2926 * Creates a logger for the given file descriptor (typically 1/stdout or 2/stderr)
2927 *
2928 * @param logger_name name of the logger
2929 * @param mask the mask to use (ie: MSG_ALL_MASK)
2930 * @param fd the file descriptor
2931 */
2932
2933 void
logger_handle_create_to_fd(const char * logger_name,int mask,int fd)2934 logger_handle_create_to_fd(const char *logger_name, int mask, int fd)
2935 {
2936 logger_channel* channel = logger_channel_alloc();
2937 output_stream stdout_os;
2938 fd_output_stream_attach(&stdout_os, dup(fd));
2939 logger_channel_stream_open(&stdout_os, FALSE, channel);
2940 logger_channel_register("stdout", channel);
2941 logger_handle_create(logger_name, &g_system_logger);
2942 logger_handle_add_channel(logger_name, mask, "stdout");
2943 }
2944
2945 s32
logger_handle_count_channels(const char * logger_name)2946 logger_handle_count_channels(const char *logger_name)
2947 {
2948 #if DEBUG_LOG_HANDLER
2949 debug_osformatln(termout, "logger_handle_count_channels(%s)", logger_name);
2950 flushout();
2951 #endif
2952
2953 logger_message *message = logger_message_alloc();
2954 s32 ret = -2;
2955
2956 #if HAS_SHARED_QUEUE_SUPPORT
2957 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2958 #else
2959 async_wait_s aw;
2960 async_wait_init(&aw, 1);
2961 #endif
2962 #if HAS_SHARED_QUEUE_SUPPORT
2963 message->pid = getpid_ex();
2964 #endif
2965 message->type = LOGGER_MESSAGE_TYPE_HANDLE_NAME_COUNT_CHANNELS;
2966 #if HAS_SHARED_QUEUE_SUPPORT
2967 message->handle_count_channels.aw = aw;
2968 #else
2969 message->handle_count_channels.aw = &aw;
2970 #endif
2971 message->handle_count_channels.logger_name = logger_name;
2972 message->handle_count_channels.countp = &ret;
2973
2974 logger_message_post(message);
2975
2976 #if HAS_SHARED_QUEUE_SUPPORT
2977 async_wait(aw);
2978 async_wait_destroy_shared(aw);
2979 #else
2980 async_wait(&aw);
2981 async_wait_finalize(&aw);
2982 #endif
2983
2984 return ret;
2985 }
2986
2987 #if DNSCORE_HAS_LOG_THREAD_TAG
2988
2989 void
logger_handle_set_thread_tag_with_pid_and_tid(pid_t pid,thread_t tid,const char tag[THREAD_TAG_SIZE])2990 logger_handle_set_thread_tag_with_pid_and_tid(pid_t pid, thread_t tid, const char tag[THREAD_TAG_SIZE])
2991 {
2992 (void)pid;
2993 #if DEBUG_LOG_HANDLER
2994 debug_osformatln(termout, "logger_handle_set_thread_tag_with_pid_and_tid(%i,%p) ", pid, tid,
2995 tag[0],tag[1],tag[2],tag[3],
2996 tag[4],tag[5],tag[6],tag[7]);
2997 flushout();
2998 #endif
2999
3000 logger_message *message = logger_message_alloc();
3001 #if HAS_SHARED_QUEUE_SUPPORT
3002 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3003 #else
3004 async_wait_s aw;
3005 async_wait_init(&aw, 1);
3006 #endif
3007 #if HAS_SHARED_QUEUE_SUPPORT
3008 message->pid = getpid_ex();
3009 #endif
3010 message->type = LOGGER_MESSAGE_TYPE_THREAD_SET_TAG;
3011 #if HAS_SHARED_QUEUE_SUPPORT
3012 message->thread_set_tag.aw = aw;
3013 #else
3014 message->thread_set_tag.aw = &aw;
3015 #endif
3016 memcpy(message->thread_set_tag.tag, tag, THREAD_TAG_SIZE);
3017 message->thread_set_tag.tid = tid;
3018
3019 logger_message_post(message);
3020
3021 #if DEBUG_LOG_HANDLER
3022 debug_osformatln(termout, "logger_handle_set_thread_tag_with_pid_and_tid(%i,%p) (posted)", pid, tid,
3023 tag[0],tag[1],tag[2],tag[3],
3024 tag[4],tag[5],tag[6],tag[7]);
3025 flushout();
3026 #endif
3027
3028 #if HAS_SHARED_QUEUE_SUPPORT
3029 async_wait(aw);
3030 async_wait_destroy_shared(aw); // does the finalize call
3031 #else
3032 async_wait(&aw);
3033 async_wait_finalize(&aw);
3034 #endif
3035 #if DEBUG_LOG_HANDLER
3036 debug_osformatln(termout, "logger_handle_set_thread_tag_with_pid_and_tid(%i,%p) (synced, done)", pid, tid,
3037 tag[0],tag[1],tag[2],tag[3],
3038 tag[4],tag[5],tag[6],tag[7]);
3039 flushout();
3040 #endif
3041 }
3042
3043 void
logger_handle_clear_thread_tag_with_pid_and_tid(pid_t pid,thread_t tid)3044 logger_handle_clear_thread_tag_with_pid_and_tid(pid_t pid, thread_t tid)
3045 {
3046 (void)pid;
3047 #if DEBUG_LOG_HANDLER
3048 debug_osformatln(termout, "logger_handle_clear_thread_tag_with_pid_and_tid(%i,%p) ", pid, tid);
3049 flushout();
3050 #endif
3051
3052 logger_message *message = logger_message_alloc();
3053
3054 #if HAS_SHARED_QUEUE_SUPPORT
3055 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3056 #else
3057 async_wait_s aw;
3058 async_wait_init(&aw, 1);
3059 #endif
3060 #if HAS_SHARED_QUEUE_SUPPORT
3061 message->pid = getpid_ex();
3062 #endif
3063 message->type = LOGGER_MESSAGE_TYPE_THREAD_CLEAR_TAG;
3064 #if HAS_SHARED_QUEUE_SUPPORT
3065 message->thread_clear_tag.aw = aw;
3066 #else
3067 message->thread_clear_tag.aw = &aw;
3068 #endif
3069 message->thread_clear_tag.tid = tid;
3070
3071 logger_message_post(message);
3072
3073 #if HAS_SHARED_QUEUE_SUPPORT
3074 async_wait(aw);
3075 async_wait_destroy_shared(aw);
3076 #else
3077 async_wait(&aw);
3078 async_wait_finalize(&aw);
3079 #endif
3080 }
3081
3082 void
logger_handle_set_thread_tag(const char tag[THREAD_TAG_SIZE])3083 logger_handle_set_thread_tag(const char tag[THREAD_TAG_SIZE])
3084 {
3085 char clean_tag[THREAD_TAG_SIZE + 1];
3086 memset(clean_tag, 0U, sizeof(clean_tag));
3087 strcpy_ex(clean_tag, tag, sizeof(clean_tag));
3088
3089 if(logger_is_running())
3090 {
3091 logger_handle_set_thread_tag_with_pid_and_tid(getpid_ex(), thread_self(), clean_tag);
3092 }
3093 else
3094 {
3095 thread_set_tag_with_pid_and_tid(getpid_ex(), thread_self(), clean_tag);
3096 }
3097 }
3098
3099 void
logger_handle_clear_thread_tag()3100 logger_handle_clear_thread_tag()
3101 {
3102 if(logger_is_running())
3103 {
3104 logger_handle_clear_thread_tag_with_pid_and_tid(getpid_ex(), thread_self());
3105 }
3106 else
3107 {
3108 thread_clear_tag_with_pid_and_tid(getpid_ex(), thread_self());
3109 }
3110 }
3111
3112 #endif
3113
3114 static u32 logger_queue_size = LOG_QUEUE_DEFAULT_SIZE;
3115
3116 #if !HAS_SHARED_QUEUE_SUPPORT
3117 u32
logger_set_queue_size(u32 n)3118 logger_set_queue_size(u32 n)
3119 {
3120 if(n < LOG_QUEUE_MIN_SIZE)
3121 {
3122 n = LOG_QUEUE_MIN_SIZE;
3123 }
3124 else if(n > LOG_QUEUE_MAX_SIZE)
3125 {
3126 n = LOG_QUEUE_MAX_SIZE;
3127 }
3128
3129 if(logger_queue_initialised && (logger_queue_size != n))
3130 {
3131 logger_queue_size = n;
3132 logger_queue_size = threaded_queue_set_maxsize(&logger_commit_queue, logger_queue_size);
3133 }
3134
3135 return logger_queue_size;
3136 }
3137 #endif
3138
3139 void
logger_init_ex(u32 queue_size,size_t shared_heap_size)3140 logger_init_ex(u32 queue_size, size_t shared_heap_size)
3141 {
3142 #if DEBUG_LOG_HANDLER
3143 debug_osformatln(termout, "logger_init_ex(%u)", queue_size);
3144 flushout();
3145 #endif
3146
3147 if(!logger_initialised())
3148 {
3149 logger_thread_pid = getpid_ex();
3150
3151 #if HAS_SHARED_QUEUE_SUPPORT
3152 shared_heap_init();
3153
3154 if(shared_heap_size == 0)
3155 {
3156 shared_heap_size = 0x4000000 + LOGGER_HANDLE_SHARED_TABLE_SIZE; // 64MB
3157 }
3158
3159 for(;;)
3160 {
3161 ya_result ret;
3162 if(ISOK(ret = shared_heap_create(shared_heap_size)))
3163 {
3164 logger_shared_heap_id = (u8)ret;
3165 break;
3166 }
3167
3168 if(shared_heap_size < 0x10000)
3169 {
3170 debug_osformatln(termerr, "logger: unable to allocate enough shared memory: %r", ret);
3171 flusherr();
3172 exit(1);
3173 }
3174
3175 shared_heap_size <<= 1;
3176 }
3177
3178 g_logger_handle_shared_table = shared_heap_alloc(logger_shared_heap_id, LOGGER_HANDLE_SHARED_TABLE_SIZE);
3179 if(g_logger_handle_shared_table == NULL)
3180 {
3181 debug_osformatln(termerr, "logger: unable to allocate handle table");
3182 flusherr();
3183 exit(1);
3184 }
3185
3186 memset(g_logger_handle_shared_table, 0U, LOGGER_HANDLE_SHARED_TABLE_SIZE);
3187
3188 for(int i = 0; i < LOGGER_HANDLE_COUNT_MAX; ++i)
3189 {
3190 for(int j = 0; j < MSG_LEVEL_COUNT; ++j)
3191 {
3192 ptr_vector_init(&g_logger_handle_shared_table[i].channels[j]);
3193 }
3194 }
3195 #endif
3196
3197 if(!logger_queue_initialised)
3198 {
3199 #if HAS_SHARED_QUEUE_SUPPORT
3200 if(queue_size == 0)
3201 {
3202 logger_queue_size = 1024 * 1024;
3203 }
3204
3205 logger_shared_queue = shared_circular_buffer_create_ex(20U, sizeof(logger_shared_space_t));
3206
3207 if(logger_shared_queue == NULL)
3208 {
3209 debug_osformatln(termerr, "logger: unable to allocate shared buffer: %r", ERRNO_ERROR);
3210 flusherr();
3211 exit(1);
3212 }
3213
3214 logger_shared_space = (logger_shared_space_t*)shared_circular_buffer_additional_space_ptr(logger_shared_queue);
3215 #else
3216 if(queue_size != 0)
3217 {
3218 logger_queue_size = queue_size;
3219 }
3220 threaded_queue_init(&logger_commit_queue, logger_queue_size); // not used anymore (replaced by a shared queue)
3221 #endif
3222 logger_queue_initialised = TRUE;
3223 }
3224
3225 if(!logger_handle_init_done)
3226 {
3227 logger_handle_init_done = TRUE;
3228
3229 ptr_vector_init(&logger_handles);
3230
3231 format_class_init();
3232 }
3233
3234 #ifndef WIN32
3235 logger_set_uid(getuid());
3236 logger_set_gid(getgid());
3237 #endif
3238
3239 logger_handle_create("system", &g_system_logger);
3240
3241 mutex_lock(&logger_mutex);
3242 _logger_initialised = TRUE;
3243 mutex_unlock(&logger_mutex);
3244 }
3245 else
3246 {
3247 #if DEBUG_LOG_HANDLER
3248 debug_osformatln(termout, "logger_init_ex(%u) : already initialised", logger_queue_size);
3249 flushout();
3250 #endif
3251 }
3252 }
3253
3254 void
logger_init()3255 logger_init()
3256 {
3257 logger_init_ex(logger_queue_size, 0 );
3258 }
3259
3260 void
logger_start()3261 logger_start()
3262 {
3263 #if DEBUG_LOG_HANDLER
3264 debug_osformatln(termout, "logger_start() ");
3265 flushout();
3266 #endif
3267
3268 ya_result return_code;
3269
3270 if(!logger_initialised())
3271 {
3272 #if DEBUG_LOG_HANDLER
3273 debug_osformatln(termout, "logger_start() : not initialised yet : calling");
3274 flushout();
3275 #endif
3276
3277 logger_init();
3278 }
3279
3280 if(logger_thread_pid != getpid_ex())
3281 {
3282 #if DEBUG_LOG_HANDLER
3283 debug_osformatln(termout, "logger_start() : not initialised by the same process");
3284 flushout();
3285 #endif
3286
3287 #if DNSCORE_HAS_LOG_THREAD_TAG
3288 // push all tags to the logger process
3289
3290 thread_tag_push_tags();
3291 #endif
3292 return;
3293 }
3294
3295 mutex_lock(&logger_mutex);
3296 if(!_logger_started)
3297 {
3298 #if DEBUG_LOG_HANDLER
3299 debug_osformatln(termout, "logger_start() : starting");
3300 flushout();
3301 #endif
3302 if((return_code = thread_create(&logger_thread_id, logger_dispatcher_thread, NULL)) != 0)
3303 {
3304 mutex_unlock(&logger_mutex);
3305 debug_osformatln(termerr, "logger_start: pthread_create: %r", return_code);
3306 DIE(LOGGER_INITIALISATION_ERROR);
3307 }
3308
3309 _logger_started = TRUE;
3310
3311 mutex_unlock(&logger_mutex);
3312 }
3313 else
3314 {
3315 mutex_unlock(&logger_mutex);
3316 #if DEBUG_LOG_HANDLER
3317 debug_osformatln(termout, "logger_start() : already started");
3318 flushout();
3319 #endif
3320 }
3321
3322 #if DEBUG_LOG_HANDLER
3323 debug_osformatln(termout, "logger_start() : started");
3324 flushout();
3325 #endif
3326 }
3327
3328 #if !HAS_SHARED_QUEUE_SUPPORT
3329 static thread_t logger_server_id = 0;
3330
3331 void
logger_start_server()3332 logger_start_server()
3333 {
3334 if(logger_initialised_and_started())
3335 {
3336 int ret;
3337 if((ret = thread_create(&logger_server_id, logger_server_dispatcher_thread, NULL)) != 0)
3338 {
3339 debug_osformatln(termerr, "logger_start_server: pthread_create: %r", ret);
3340 DIE(LOGGER_INITIALISATION_ERROR);
3341 }
3342 }
3343 }
3344
3345 void
logger_stop_server()3346 logger_stop_server()
3347 {
3348 pthread_cancel(logger_server_id);
3349 }
3350
3351 void
logger_start_client()3352 logger_start_client()
3353 {
3354 #if DEBUG_LOG_HANDLER
3355 debug_osformatln(termout, "logger_start_client() ");
3356 flushout();
3357 #endif
3358
3359 ya_result ret;
3360
3361 if(!logger_initialised())
3362 {
3363 #if DEBUG_LOG_HANDLER
3364 debug_osformatln(termout, "logger_start_client() : not initialised yet : calling");
3365 flushout();
3366 #endif
3367
3368 logger_init();
3369 }
3370
3371 if(!logger_started())
3372 {
3373 #if DEBUG_LOG_HANDLER
3374 debug_osformatln(termout, "logger_start_client() : starting");
3375 flushout();
3376 #endif
3377
3378 if((ret = thread_create(&logger_thread_id, logger_client_dispatcher_thread, NULL)) != 0)
3379 {
3380 debug_osformatln(termerr, "logger_start: pthread_create: %r", ret);
3381 DIE(LOGGER_INITIALISATION_ERROR);
3382 }
3383
3384 logger_is_client = TRUE;
3385 logger_started = TRUE;
3386 }
3387 else
3388 {
3389 #if DEBUG_LOG_HANDLER
3390 debug_osformatln(termout, "logger_start_client() : already started");
3391 flushout();
3392 #endif
3393 }
3394
3395 #if DEBUG_LOG_HANDLER
3396 debug_osformatln(termout, "logger_start_client() : started");
3397 flushout();
3398 #endif
3399 }
3400
3401 void
logger_stop_client()3402 logger_stop_client()
3403 {
3404 logger_stop();
3405 //pthread_cancel(logger_thread_id);
3406 }
3407
3408 #endif
3409
3410 static void
logger_send_message_stop_wait()3411 logger_send_message_stop_wait()
3412 {
3413 #if DEBUG_LOG_HANDLER
3414 debug_osformatln(termout, "logger_send_message_stop_wait()");
3415 flushout();
3416 #endif
3417
3418 #if HAS_SHARED_QUEUE_SUPPORT
3419 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3420 #else
3421 async_wait_s aw;
3422 async_wait_init(&aw, 1);
3423 #endif
3424
3425 logger_message* message = logger_message_alloc();
3426 #if HAS_SHARED_QUEUE_SUPPORT
3427 message->pid = getpid_ex();
3428 #endif
3429 message->type = LOGGER_MESSAGE_TYPE_STOP;
3430 #if HAS_SHARED_QUEUE_SUPPORT
3431 message->stop.aw = aw;
3432 #else
3433 message->stop.aw = &aw;
3434 #endif
3435
3436 logger_message_post(message);
3437
3438 #if DEBUG_LOG_HANDLER
3439 debug_osformatln(termout, "logger_send_message_stop_wait() : waiting");
3440 flushout();
3441 #endif
3442
3443 #if HAS_SHARED_QUEUE_SUPPORT
3444 async_wait(aw);
3445 async_wait_destroy_shared(aw);
3446 #else
3447 async_wait(&aw);
3448 async_wait_finalize(&aw);
3449 #endif
3450
3451 #if DEBUG_LOG_HANDLER
3452 debug_osformatln(termout, "logger_send_message_stop_wait() : should be stopped");
3453 flushout();
3454 #endif
3455 }
3456
3457 u8
logger_set_shared_heap(u8 id)3458 logger_set_shared_heap(u8 id)
3459 {
3460 u8 ret = logger_shared_heap_id;
3461 logger_shared_heap_id = id;
3462 return ret;
3463 }
3464
3465 void
logger_stop()3466 logger_stop()
3467 {
3468 #if DEBUG_LOG_HANDLER
3469 debug_osformatln(termout, "logger_stop()");
3470 flushout();
3471 #endif
3472
3473 if(logger_initialised_and_started())
3474 {
3475 // send the stop order
3476
3477 if(logger_thread_pid == getpid_ex())
3478 {
3479 logger_send_message_stop_wait();
3480
3481 #if DEBUG_LOG_HANDLER
3482 debug_osformatln(termout, "logger_stop() : joining");
3483 flushout();
3484 #endif
3485
3486 // wait for the end
3487
3488 ya_result return_code;
3489
3490 if((return_code = thread_join(logger_thread_id, NULL)) != 0)
3491 {
3492 flushout();
3493 flusherr();
3494 debug_osformatln(termerr, "logger_stop: thread_join: %r", return_code);
3495 flusherr();
3496 }
3497
3498 logger_thread_id = 0;
3499 mutex_lock(&logger_mutex);
3500 _logger_started = FALSE;
3501 mutex_unlock(&logger_mutex);
3502 }
3503 else
3504 {
3505 // not the owner
3506 }
3507 }
3508
3509 #if DEBUG_LOG_HANDLER
3510 debug_osformatln(termout, "logger_stop() : stopped");
3511 flushout();
3512 #endif
3513 }
3514
3515 void
logger_finalize()3516 logger_finalize()
3517 {
3518 #if DEBUG_LOG_HANDLER
3519 debug_osformatln(termout, "logger_finalize()");
3520 flushout();
3521 #endif
3522
3523 if(logger_thread_pid != getpid_ex())
3524 {
3525 #if DEBUG_LOG_HANDLER
3526 debug_osformatln(termout, "logger_finalize() : not owner");
3527 flushout();
3528 #endif
3529 return;
3530 }
3531
3532 if(!logger_initialised())
3533 {
3534 #if DEBUG_LOG_HANDLER
3535 debug_osformatln(termout, "logger_finalize() : not initialised");
3536 flushout();
3537 #endif
3538 return;
3539 }
3540
3541 #if HAS_SHARED_QUEUE_SUPPORT
3542 if(!shared_circular_buffer_empty(logger_shared_queue))
3543 {
3544 #if DEBUG_LOG_HANDLER
3545 debug_osformatln(termout, "logger_finalize() : queue is not empty : starting & flushing");
3546 flushout();
3547 #endif
3548 if(!logger_started())
3549 {
3550 logger_start();
3551 if(logger_wait_started())
3552 {
3553 logger_flush();
3554 }
3555 }
3556 else
3557 {
3558 logger_flush();
3559 }
3560 }
3561 #else
3562 if(threaded_queue_size(&logger_commit_queue) > 0)
3563 {
3564 #if DEBUG_LOG_HANDLER
3565 debug_osformatln(termout, "logger_finalize() : queue is not empty : starting & flushing");
3566 flushout();
3567 #endif
3568 logger_start();
3569 logger_flush();
3570 }
3571 #endif
3572
3573 if(logger_started())
3574 {
3575 #if DEBUG_LOG_HANDLER
3576 debug_osformatln(termout, "logger_finalize() : still running : stopping");
3577 flushout();
3578 #endif
3579 logger_stop();
3580 }
3581
3582 /*
3583 * Ensure there is nothing left at all in the queue
3584 */
3585
3586 #if HAS_SHARED_QUEUE_SUPPORT
3587 while(!shared_circular_buffer_empty(logger_shared_queue))
3588 {
3589 logger_message* message = (logger_message*)shared_circular_buffer_prepare_dequeue(logger_shared_queue);
3590 if(message->type == LOGGER_MESSAGE_TYPE_TEXT)
3591 {
3592 shared_heap_free(message->text.text);
3593 }
3594 shared_circular_buffer_commit_dequeue(logger_shared_queue);
3595 }
3596 #else
3597 while(threaded_queue_size(&logger_commit_queue) > 0)
3598 {
3599 logger_message* message = threaded_queue_dequeue(&logger_commit_queue);
3600
3601 #if DEBUG_LOG_HANDLER
3602 debug_osformatln(termout, "logger_finalize() : freeing message of type %u", message->type);
3603 flushout();
3604 #endif
3605
3606 if(message->type == LOGGER_MESSAGE_TYPE_TEXT)
3607 {
3608 ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
3609 }
3610 logger_message_free(message);
3611 }
3612 #endif
3613
3614 if(logger_handle_init_done)
3615 {
3616 #if DEBUG_LOG_HANDLER
3617 debug_osformatln(termout, "logger_finalize() : flushing all channels");
3618 flushout();
3619 #endif
3620 logger_service_flush_all_channels();
3621
3622 // closes all handles
3623
3624 if(logger_thread_pid == getpid_ex()) // logger_handle_owner_pid
3625 {
3626 #if DEBUG_LOG_HANDLER
3627 debug_osformatln(termout, "logger_finalize() : closing all handles");
3628 flushout();
3629 #endif
3630 ptr_vector_callback_and_clear(&logger_handles, logger_handle_free);
3631 ptr_vector_destroy(&logger_handles);
3632
3633 // closes all channels
3634
3635 #if DEBUG_LOG_HANDLER
3636 debug_osformatln(termout, "logger_finalize() : closing all channels");
3637 flushout();
3638 #endif
3639
3640 logger_service_channel_unregister_all();
3641 }
3642
3643 logger_handle_init_done = FALSE;
3644 }
3645
3646 if(logger_queue_initialised)
3647 {
3648 #if HAS_SHARED_QUEUE_SUPPORT
3649 shared_circular_buffer_destroy(logger_shared_queue);
3650 #else
3651 threaded_queue_finalize(&logger_commit_queue);
3652 #endif
3653 logger_queue_initialised = FALSE;
3654 }
3655
3656 logger_set_path(NULL);
3657
3658 mutex_lock(&logger_mutex);
3659 _logger_initialised = FALSE;
3660 mutex_unlock(&logger_mutex);
3661
3662 #if DEBUG_LOG_HANDLER
3663 debug_osformatln(termout, "logger_finalize() : finalised");
3664 flushout();
3665 #endif
3666 }
3667
3668 void
logger_flush()3669 logger_flush()
3670 {
3671 #if DEBUG_LOG_HANDLER > 1
3672 debug_osformatln(termout, "logger_flush()");
3673 flushout();
3674 #endif
3675
3676 if(logger_initialised_and_started())
3677 {
3678 if(logger_thread_id != thread_self())
3679 {
3680 #if HAS_SHARED_QUEUE_SUPPORT
3681 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3682 #else
3683 async_wait_s aw;
3684 async_wait_init(&aw, 1);
3685 #endif
3686 logger_message* message = logger_message_alloc();
3687 #if DEBUG
3688 message->align0 = 0xde;
3689 message->align1 = 0xf00d;
3690 #endif
3691 #if HAS_SHARED_QUEUE_SUPPORT
3692 message->pid = getpid_ex();
3693 #endif
3694 message->channel_flush_all.tid = thread_self();
3695 message->type = LOGGER_MESSAGE_TYPE_CHANNEL_FLUSH_ALL;
3696
3697 #if HAS_SHARED_QUEUE_SUPPORT
3698 message->channel_flush_all.aw = aw;
3699 #else
3700 message->channel_flush_all.aw = &aw;
3701 #endif
3702 logger_message_post(message);
3703
3704 // avoid being stuck forever if the service is down
3705
3706 while(logger_initialised_and_started())
3707 {
3708 #if HAS_SHARED_QUEUE_SUPPORT
3709 if(async_wait_timeout(aw, ONE_SECOND_US))
3710 {
3711 //async_wait_destroy_shared(aw);
3712 break;
3713 }
3714 #else
3715 if(async_wait_timeout(&aw, ONE_SECOND_US))
3716 {
3717 async_wait_finalize(&aw);
3718 break;
3719 }
3720 #endif
3721 }
3722
3723 async_wait_destroy_shared(aw);
3724 }
3725 else
3726 {
3727 logger_service_flush_all_channels();
3728 }
3729 }
3730 #if DEBUG_LOG_HANDLER
3731 else
3732 {
3733 debug_osformatln(termout, "logger_flush() : i=%i s=%i", logger_initialised, logger_started());
3734 flushout();
3735 }
3736 #endif
3737 }
3738
3739 void
logger_channel_close_all()3740 logger_channel_close_all()
3741 {
3742 #if DEBUG_LOG_HANDLER
3743 debug_osformatln(termout, "logger_close_all_channels()");
3744 flushout();
3745 #endif
3746
3747 if(logger_initialised_and_started())
3748 {
3749 #if HAS_SHARED_QUEUE_SUPPORT
3750 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3751 #else
3752 async_wait_s aw;
3753 async_wait_init(&aw, 1);
3754 #endif
3755
3756 logger_message* message = logger_message_alloc();
3757
3758 #if DEBUG
3759 ZEROMEMORY(message, sizeof(logger_message));
3760 #endif
3761 #if HAS_SHARED_QUEUE_SUPPORT
3762 message->pid = getpid_ex();
3763 #endif
3764 message->type = LOGGER_MESSAGE_TYPE_CHANNEL_CLOSE_ALL;
3765 #if HAS_SHARED_QUEUE_SUPPORT
3766 message->channel_flush_all.aw = aw;
3767 #else
3768 message->channel_flush_all.aw = &aw;
3769 #endif
3770
3771 logger_message_post(message);
3772
3773 // avoid being stuck forever if the service is down
3774
3775 while(logger_initialised_and_started())
3776 {
3777 #if HAS_SHARED_QUEUE_SUPPORT
3778 formatln("logger_channel_close_all");
3779 if(async_wait_timeout(aw, ONE_SECOND_US))
3780 {
3781 //async_wait_destroy_shared(aw);
3782 break;
3783 }
3784 #else
3785 if(async_wait_timeout(&aw, ONE_SECOND_US))
3786 {
3787 async_wait_finalize(&aw);
3788 break;
3789 }
3790 #endif
3791 }
3792
3793 async_wait_destroy_shared(aw);
3794 }
3795 #if DEBUG_LOG_HANDLER
3796 else
3797 {
3798 debug_osformatln(termout, "logger_close_all_channels() : i=%i s=%i", logger_initialised, logger_started());
3799 flushout();
3800 }
3801 #endif
3802 }
3803
3804 void
logger_reopen()3805 logger_reopen()
3806 {
3807 #if DEBUG_LOG_HANDLER
3808 debug_osformatln(termout, "logger_reopen()");
3809 flushout();
3810 #endif
3811
3812 if(logger_initialised_and_started())
3813 {
3814 // even for a lflag, the message NEEDS to be enqueued because
3815 // 1) it activates the service
3816 // 2) synchronises the memory between the threads (memory wall)
3817
3818 #if HAS_SHARED_QUEUE_SUPPORT
3819 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3820 #else
3821 async_wait_s aw;
3822 async_wait_init(&aw, 1);
3823 #endif
3824
3825 logger_message* message = logger_message_alloc();
3826
3827 #if DEBUG
3828 ZEROMEMORY(message, sizeof(logger_message));
3829 #endif
3830 #if HAS_SHARED_QUEUE_SUPPORT
3831 message->pid = getpid_ex();
3832 #endif
3833 message->type = LOGGER_MESSAGE_TYPE_CHANNEL_REOPEN_ALL;
3834 #if HAS_SHARED_QUEUE_SUPPORT
3835 message->channel_reopen_all.aw = aw;
3836 #else
3837 message->channel_reopen_all.aw = &aw;
3838 #endif
3839 mutex_lock(&logger_mutex);
3840 logger_shared_space->_logger_reopen_request_message = message;
3841 mutex_unlock(&logger_mutex);
3842
3843 logger_message_post(message);
3844
3845 while(logger_initialised_and_started())
3846 {
3847 #if HAS_SHARED_QUEUE_SUPPORT
3848 #if DEBUG_LOG_HANDLER
3849 formatln("logger_reopen");
3850 #endif
3851 if(async_wait_timeout(aw, ONE_SECOND_US))
3852 {
3853 //async_wait_destroy_shared(aw);
3854 break;
3855 }
3856 #else
3857 if(async_wait_timeout(&aw, ONE_SECOND_US))
3858 {
3859 async_wait_finalize(&aw);
3860 break;
3861 }
3862 #endif
3863 }
3864
3865 async_wait_destroy_shared(aw);
3866 }
3867 #if DEBUG_LOG_HANDLER
3868 else
3869 {
3870 debug_osformatln(termout, "logger_reopen() : i=%i s=%i", logger_initialised, logger_started());
3871 flushout();
3872 }
3873 #endif
3874 }
3875
3876 void
logger_sink_noblock()3877 logger_sink_noblock()
3878 {
3879 mutex_lock(&logger_mutex);
3880 logger_shared_space->_logger_sink_request_message = LOGGER_MESSAGE_SINK_FAKE;
3881 mutex_unlock(&logger_mutex);
3882 }
3883
3884 void
logger_sink()3885 logger_sink()
3886 {
3887 #if DEBUG_LOG_HANDLER
3888 debug_osformatln(termout, "logger_reopen()");
3889 flushout();
3890 #endif
3891
3892 if(logger_initialised_and_started())
3893 {
3894 // even for a lflag, the message NEEDS to be enqueued because
3895 // 1) it activates the service
3896 // 2) synchronises the memory between the threads (memory wall)
3897
3898 #if HAS_SHARED_QUEUE_SUPPORT
3899 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3900 #else
3901 async_wait_s aw;
3902 async_wait_init(&aw, 1);
3903 #endif
3904 logger_message* message = logger_message_alloc();
3905 #if DEBUG
3906 ZEROMEMORY(message, sizeof(logger_message));
3907 #endif
3908 #if HAS_SHARED_QUEUE_SUPPORT
3909 message->pid = getpid_ex();
3910 #endif
3911 message->type = LOGGER_MESSAGE_TYPE_CHANNEL_SINK_ALL;
3912 #if HAS_SHARED_QUEUE_SUPPORT
3913 message->channel_sink_all.aw = aw;
3914 #else
3915 message->channel_sink_all.aw = &aw;
3916 #endif
3917 mutex_lock(&logger_mutex);
3918 logger_shared_space->_logger_sink_request_message = message;
3919 mutex_unlock(&logger_mutex);
3920
3921 logger_message_post(message);
3922
3923 while(logger_initialised_and_started())
3924 {
3925 #if HAS_SHARED_QUEUE_SUPPORT
3926 #if DEBUG
3927 formatln("logger_sink");
3928 #endif
3929 if(async_wait_timeout(aw, ONE_SECOND_US))
3930 {
3931 //async_wait_destroy_shared(aw);
3932 break;
3933 }
3934 #else
3935 if(async_wait_timeout(&aw, ONE_SECOND_US))
3936 {
3937 async_wait_finalize(&aw);
3938 break;
3939 }
3940 #endif
3941 #if DEBUG
3942 mutex_lock(&logger_mutex);
3943 bool stop_looping = logger_shared_space->_logger_sink_request_message != NULL;
3944 mutex_unlock(&logger_mutex);
3945 if(stop_looping)
3946 {
3947 formatln("_logger_sink_requested is FALSE but the synchronization hasn't been released yet");
3948 }
3949 #endif
3950 }
3951
3952 async_wait_destroy_shared(aw);
3953 }
3954 #if DEBUG_LOG_HANDLER
3955 else
3956 {
3957 debug_osformatln(termout, "logger_reopen() : i=%i s=%i", logger_initialised, logger_started());
3958 flushout();
3959 }
3960 #endif
3961 }
3962
3963 bool
logger_is_running()3964 logger_is_running()
3965 {
3966 return logger_started();
3967 }
3968
3969 void
logger_handle_vmsg(logger_handle * handle,u32 level,const char * fmt,va_list args)3970 logger_handle_vmsg(logger_handle* handle, u32 level, const char* fmt, va_list args)
3971 {
3972 /*
3973 * check that the handle has got a channel for the level
3974 */
3975
3976 #if DEBUG
3977 if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
3978 {
3979 #if DEBUG_LOG_HANDLER
3980 debug_stacktrace_print(termout, debug_stacktrace_get());
3981 debug_stacktrace_print(termerr, debug_stacktrace_get());
3982 flushout();
3983 flusherr();
3984 #endif
3985 abort();
3986 }
3987
3988 if(level >= MSG_LEVEL_COUNT)
3989 {
3990 debug_osformatln(termerr, "bad message level %u", level);
3991 logger_handle_trigger_emergency_shutdown();
3992 return;
3993 }
3994
3995 if(level <= MSG_ERR)
3996 {
3997 sleep(0);
3998 }
3999
4000 #endif
4001
4002 if(handle == NULL)
4003 {
4004 if(level <= exit_level)
4005 {
4006 logger_handle_trigger_emergency_shutdown();
4007 }
4008 return;
4009 }
4010
4011 if(level > logger_level)
4012 {
4013 return;
4014 }
4015
4016 s32 channel_count = handle->channels[level].offset;
4017
4018 if(channel_count < 0) /* it's count-1 actually */
4019 {
4020 return;
4021 }
4022
4023 /**
4024 * @note At this point we KNOW we have to print something.
4025 */
4026
4027 output_stream baos;
4028 #if HAS_SHARED_QUEUE_SUPPORT
4029 shared_heap_output_stream_context shos_context;
4030 #else
4031 bytezarray_output_stream_context baos_context;
4032 #endif
4033
4034 /*
4035 * DEFAULT_MAX_LINE_SIZE is the base size.
4036 *
4037 * The output stream has the BYTEARRAY_DYNAMIC flag set in order to allow
4038 * bigger sentences.
4039 *
4040 */
4041
4042 /* Will use the tmp buffer, but alloc a bigger one if required. */
4043 #if HAS_SHARED_QUEUE_SUPPORT
4044 shared_heap_output_stream_init_ex_static(&baos, logger_shared_heap_id, NULL, 48, SHARED_HEAP_DYNAMIC, &shos_context);
4045 #else
4046 bytezarray_output_stream_init_ex_static(&baos, NULL, DEFAULT_MAX_LINE_SIZE, BYTEARRAY_DYNAMIC, &baos_context);
4047 #endif
4048
4049 if(FAIL(vosformat(&baos, fmt, args)))
4050 {
4051 #if HAS_SHARED_QUEUE_SUPPORT
4052 shared_heap_output_stream_reset(&baos);
4053 #else
4054 bytezarray_output_stream_reset(&baos);
4055 #endif
4056 osprint(&baos, "*** ERROR : MESSAGE FORMATTING FAILED ***");
4057 }
4058
4059 output_stream_write_u8(&baos, 0);
4060
4061 logger_message* message = logger_message_alloc();
4062
4063 #if HAS_SHARED_QUEUE_SUPPORT
4064 message->pid = getpid_ex();
4065 #endif
4066 message->type = LOGGER_MESSAGE_TYPE_TEXT;
4067 message->text.level = level;
4068 message->text.flags = 0;
4069
4070 #if HAS_SHARED_QUEUE_SUPPORT
4071 message->text.text_length = shared_heap_output_stream_size(&baos) - 1;
4072 message->text.text_buffer_length = shared_heap_output_stream_buffer_size(&baos);
4073 #else
4074 message->text.text_length = bytezarray_output_stream_size(&baos) - 1;
4075 message->text.text_buffer_length = bytezarray_output_stream_buffer_size(&baos);
4076 #endif
4077
4078 message->text.handle = handle;
4079
4080 #if HAS_SHARED_QUEUE_SUPPORT
4081 message->text.text = shared_heap_output_stream_detach(&baos);
4082 #else
4083 message->text.text = bytezarray_output_stream_detach(&baos);
4084 #endif
4085
4086 #if SIZEOF_TIMEVAL <= 8
4087 gettimeofday(&message->text.tv, NULL);
4088 #else
4089 message->text.timestamp = timeus();
4090 #endif
4091
4092 #if !HAS_SHARED_QUEUE_SUPPORT
4093 // prefix
4094 // prefix_len
4095
4096 message->text.rc = 0;
4097
4098 #if DEBUG || HAS_LOG_PID
4099 message->text.pid = getpid_ex();
4100 #endif
4101 #endif
4102
4103 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4104 message->text.thread_id = thread_self();
4105 #endif
4106
4107 logger_message_post(message);
4108
4109 output_stream_close(&baos); /* Frees the memory */
4110
4111 if(level <= exit_level)
4112 {
4113 logger_handle_trigger_emergency_shutdown();
4114 }
4115 }
4116
4117 void
logger_handle_msg_nocull(logger_handle * handle,u32 level,const char * fmt,...)4118 logger_handle_msg_nocull(logger_handle* handle, u32 level, const char* fmt, ...)
4119 {
4120 /**
4121 * @note At this point we KNOW we have to print something.
4122 */
4123
4124 #if DEBUG
4125
4126 if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4127 {
4128 #if DEBUG_LOG_HANDLER
4129 debug_stacktrace_print(termout, debug_stacktrace_get());
4130 debug_stacktrace_print(termerr, debug_stacktrace_get());
4131 flushout();
4132 flusherr();
4133 #endif
4134 abort();
4135 }
4136
4137 #ifdef NDEBUG
4138 size_t sizeof_logger_message = sizeof(logger_message);
4139 size_t sizeof_logger_message_text_s = sizeof(struct logger_message_text_s);
4140 assert(sizeof_logger_message_text_s <= 64);
4141 assert(sizeof_logger_message <= 64);
4142 (void)sizeof_logger_message;
4143 (void)sizeof_logger_message_text_s;
4144 #endif
4145
4146 #endif
4147
4148 output_stream baos;
4149 #if HAS_SHARED_QUEUE_SUPPORT
4150 shared_heap_output_stream_context shos_context;
4151 #else
4152 bytezarray_output_stream_context baos_context;
4153 #endif
4154 /*
4155 * DEFAULT_MAX_LINE_SIZE is the base size.
4156 *
4157 * The output stream has the BYTEARRAY_DYNAMIC flag set in order to allow
4158 * bigger sentences.
4159 *
4160 */
4161
4162 va_list args;
4163 va_start(args, fmt);
4164
4165 /* Will use the tmp buffer, but alloc a bigger one if required. */
4166 #if HAS_SHARED_QUEUE_SUPPORT
4167 shared_heap_output_stream_init_ex_static(&baos, logger_shared_heap_id, NULL, 48, SHARED_HEAP_DYNAMIC, &shos_context);
4168 #else
4169 bytezarray_output_stream_init_ex_static(&baos, NULL, DEFAULT_MAX_LINE_SIZE, BYTEARRAY_DYNAMIC, &baos_context);
4170 #endif
4171
4172 if(FAIL(vosformat(&baos, fmt, args)))
4173 {
4174 #if HAS_SHARED_QUEUE_SUPPORT
4175 shared_heap_output_stream_reset(&baos);
4176 #else
4177 bytezarray_output_stream_reset(&baos);
4178 #endif
4179 osprint(&baos, "*** ERROR : MESSAGE FORMATTING FAILED ***");
4180 }
4181
4182 output_stream_write_u8(&baos, 0);
4183
4184 logger_message* message = logger_message_alloc();
4185
4186 #if HAS_SHARED_QUEUE_SUPPORT
4187 message->pid = getpid_ex();
4188 #endif
4189 message->type = LOGGER_MESSAGE_TYPE_TEXT;
4190 message->text.level = level;
4191 message->text.flags = 0;
4192
4193 #if HAS_SHARED_QUEUE_SUPPORT
4194 message->text.text_length = shared_heap_output_stream_size(&baos) - 1;
4195 message->text.text_buffer_length = shared_heap_output_stream_buffer_size(&baos);
4196 #else
4197 message->text.text_length = bytezarray_output_stream_size(&baos) - 1;
4198 message->text.text_buffer_length = bytezarray_output_stream_buffer_size(&baos);
4199 #endif
4200
4201 message->text.handle = handle;
4202
4203 #if HAS_SHARED_QUEUE_SUPPORT
4204 message->text.text = shared_heap_output_stream_detach(&baos);
4205 #else
4206 message->text.text = bytezarray_output_stream_detach(&baos);
4207 #endif
4208
4209 assert(message->text.text != NULL);
4210
4211 #if SIZEOF_TIMEVAL <= 8
4212 gettimeofday(&message->text.tv, NULL);
4213 #else
4214 message->text.timestamp = timeus();
4215 #endif
4216
4217 // prefix
4218 // prefix_len
4219
4220 #if !HAS_SHARED_QUEUE_SUPPORT
4221 message->text.rc = 0;
4222
4223 #if DEBUG || HAS_LOG_PID
4224 message->text.pid = getpid_ex();
4225 #endif
4226 #endif
4227
4228 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4229 message->text.thread_id = thread_self();
4230 #endif
4231
4232 logger_message_post(message);
4233
4234 va_end(args);
4235
4236 output_stream_close(&baos); /* Frees the memory */
4237 }
4238
4239
4240 void
logger_handle_msg(logger_handle * handle,u32 level,const char * fmt,...)4241 logger_handle_msg(logger_handle* handle, u32 level, const char* fmt, ...)
4242 {
4243 /*
4244 * check that the handle has got a channel for the level
4245 */
4246
4247 #if DEBUG
4248 if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4249 {
4250 #if DEBUG_LOG_HANDLER
4251 debug_stacktrace_print(termout, debug_stacktrace_get());
4252 debug_stacktrace_print(termerr, debug_stacktrace_get());
4253 flushout();
4254 flusherr();
4255 #endif
4256 abort();
4257 }
4258
4259 if(level >= MSG_LEVEL_COUNT)
4260 {
4261 debug_osformatln(termerr, "bad message level %u", level);
4262 logger_handle_trigger_emergency_shutdown();
4263 return;
4264 }
4265
4266 if(level <= MSG_ERR)
4267 {
4268 sleep(0);
4269 }
4270
4271 #endif
4272
4273 if(handle == NULL)
4274 {
4275 if(level <= exit_level)
4276 {
4277 logger_handle_trigger_emergency_shutdown();
4278 }
4279 return;
4280 }
4281
4282 if(level > logger_level)
4283 {
4284 return;
4285 }
4286
4287 s32 channel_count = handle->channels[level].offset;
4288
4289 if(channel_count < 0) /* it's count-1 actually */
4290 {
4291 return;
4292 }
4293
4294 /**
4295 * @note At this point we KNOW we have to print something.
4296 */
4297
4298 output_stream baos;
4299 #if HAS_SHARED_QUEUE_SUPPORT
4300 shared_heap_output_stream_context baos_context;
4301 #else
4302 bytezarray_output_stream_context baos_context;
4303 #endif
4304
4305 /*
4306 * DEFAULT_MAX_LINE_SIZE is the base size.
4307 *
4308 * The output stream has the BYTEARRAY_DYNAMIC flag set in order to allow
4309 * bigger sentences.
4310 *
4311 */
4312
4313 va_list args;
4314 va_start(args, fmt);
4315
4316 /* Will use the tmp buffer, but alloc a bigger one if required. */
4317 #if HAS_SHARED_QUEUE_SUPPORT
4318 shared_heap_output_stream_init_ex_static(&baos, logger_shared_heap_id, NULL, DEFAULT_MAX_LINE_SIZE, SHARED_HEAP_DYNAMIC, &baos_context);
4319 #else
4320 bytezarray_output_stream_init_ex_static(&baos, NULL, DEFAULT_MAX_LINE_SIZE, BYTEARRAY_DYNAMIC, &baos_context);
4321 #endif
4322
4323 if(FAIL(vosformat(&baos, fmt, args)))
4324 {
4325 #if HAS_SHARED_QUEUE_SUPPORT
4326 shared_heap_output_stream_reset(&baos);
4327 #else
4328 bytezarray_output_stream_reset(&baos);
4329 #endif
4330 osprint(&baos, "*** ERROR : MESSAGE FORMATTING FAILED ***");
4331 }
4332
4333 output_stream_write_u8(&baos, 0);
4334
4335 logger_message* message = logger_message_alloc();
4336
4337 #if HAS_SHARED_QUEUE_SUPPORT
4338 message->pid = getpid_ex();
4339 #endif
4340 message->type = LOGGER_MESSAGE_TYPE_TEXT;
4341 message->text.level = level;
4342 message->text.flags = 0;
4343
4344 #if HAS_SHARED_QUEUE_SUPPORT
4345 message->text.text_length = shared_heap_output_stream_size(&baos) - 1;
4346 message->text.text_buffer_length = shared_heap_output_stream_buffer_size(&baos);
4347 #else
4348 message->text.text_length = bytezarray_output_stream_size(&baos) - 1;
4349 message->text.text_buffer_length = bytezarray_output_stream_buffer_size(&baos);
4350 #endif
4351
4352 message->text.handle = handle;
4353
4354 #if HAS_SHARED_QUEUE_SUPPORT
4355 message->text.text = shared_heap_output_stream_detach(&baos);
4356 #else
4357 message->text.text = bytezarray_output_stream_detach(&baos);
4358 #endif
4359
4360 assert(message->text.text != NULL);
4361
4362 #if SIZEOF_TIMEVAL <= 8
4363 gettimeofday(&message->text.tv, NULL);
4364 #else
4365 message->text.timestamp = timeus();
4366 #endif
4367
4368 // prefix
4369 // prefix_len
4370
4371 #if !HAS_SHARED_QUEUE_SUPPORT
4372 message->text.rc = 0;
4373
4374 #if DEBUG || HAS_LOG_PID
4375 message->text.pid = getpid_ex();
4376 #endif
4377 #endif
4378
4379 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4380 message->text.thread_id = thread_self();
4381 #endif
4382
4383 logger_message_post(message);
4384
4385 va_end(args);
4386
4387 output_stream_close(&baos); /* Frees the memory */
4388
4389 if(level <= exit_level)
4390 {
4391 exit_level = 0;
4392 if(!dnscore_shuttingdown())
4393 {
4394 logger_handle_trigger_emergency_shutdown();
4395 }
4396 }
4397 }
4398
4399 void
logger_handle_msg_text(logger_handle * handle,u32 level,const char * text,u32 text_len)4400 logger_handle_msg_text(logger_handle* handle, u32 level, const char* text, u32 text_len)
4401 {
4402 /*
4403 * check that the handle has got a channel for the level
4404 */
4405
4406 #if DEBUG
4407 if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4408 {
4409 #if DEBUG_LOG_HANDLER
4410 debug_stacktrace_print(termout, debug_stacktrace_get());
4411 debug_stacktrace_print(termerr, debug_stacktrace_get());
4412 flushout();
4413 flusherr();
4414 #endif
4415 abort();
4416 }
4417
4418 if(level >= MSG_LEVEL_COUNT)
4419 {
4420 debug_osformatln(termerr, "bad message level %u", level);
4421 logger_handle_trigger_emergency_shutdown();
4422 return;
4423 }
4424
4425 if(level <= MSG_ERR)
4426 {
4427 sleep(0);
4428 }
4429
4430 #endif
4431
4432 if(handle == NULL)
4433 {
4434 if(level <= exit_level)
4435 {
4436 logger_handle_trigger_emergency_shutdown();
4437 }
4438 return;
4439 }
4440
4441 if(level > logger_level)
4442 {
4443 return;
4444 }
4445
4446 s32 channel_count = handle->channels[level].offset;
4447
4448 if(channel_count < 0) /* it's count-1 actually */
4449 {
4450 return;
4451 }
4452
4453 logger_message* message = logger_message_alloc();
4454
4455 #if HAS_SHARED_QUEUE_SUPPORT
4456 message->pid = getpid_ex();
4457 #endif
4458 message->type = LOGGER_MESSAGE_TYPE_TEXT;
4459 message->text.level = level;
4460 message->text.flags = 0;
4461
4462 message->text.text_length = text_len;
4463 message->text.text_buffer_length = text_len;
4464 message->text.handle = handle;
4465
4466 #if HAS_SHARED_QUEUE_SUPPORT
4467 message->text.text = (u8*)shared_heap_wait_alloc(logger_shared_heap_id, text_len);
4468 #else
4469 ZALLOC_ARRAY_OR_DIE(u8*, message->text. text, text_len, LOGRTEXT_TAG);
4470 #endif
4471 assert(message->text.text != NULL);
4472
4473 memcpy(message->text.text, text, text_len);
4474
4475 #if SIZEOF_TIMEVAL <= 8
4476 gettimeofday(&message->text.tv, NULL);
4477 #else
4478 message->text.timestamp = timeus();
4479 #endif
4480
4481 // prefix
4482 // prefix_len
4483
4484 #if !HAS_SHARED_QUEUE_SUPPORT
4485 message->text.rc = 0;
4486
4487 #if DEBUG || HAS_LOG_PID
4488 message->text.pid = getpid_ex();
4489 #endif
4490 #endif
4491
4492 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4493 message->text.thread_id = thread_self();
4494 #endif
4495
4496 logger_message_post(message);
4497
4498 if(level <= exit_level)
4499 {
4500 logger_handle_trigger_emergency_shutdown();
4501 }
4502 }
4503
4504 void
logger_handle_msg_text_ext(logger_handle * handle,u32 level,const char * text,u32 text_len,const char * prefix,u32 prefix_len,u16 flags)4505 logger_handle_msg_text_ext(logger_handle* handle, u32 level, const char* text, u32 text_len, const char* prefix, u32 prefix_len, u16 flags)
4506 {
4507 /*
4508 * check that the handle has got a channel for the level
4509 */
4510
4511 #if DEBUG
4512 if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4513 {
4514 #if DEBUG_LOG_HANDLER
4515 debug_stacktrace_print(termout, debug_stacktrace_get());
4516 debug_stacktrace_print(termerr, debug_stacktrace_get());
4517 flushout();
4518 flusherr();
4519 #endif
4520 abort();
4521 }
4522
4523 if(level >= MSG_LEVEL_COUNT)
4524 {
4525 debug_osformatln(termerr, "bad message level %u", level);
4526 logger_handle_trigger_emergency_shutdown();
4527 return;
4528 }
4529
4530 if(level <= MSG_ERR)
4531 {
4532 sleep(0);
4533 }
4534
4535 #endif
4536
4537 if(handle == NULL)
4538 {
4539 if(level <= exit_level)
4540 {
4541 logger_handle_trigger_emergency_shutdown();
4542 }
4543 return;
4544 }
4545
4546 if(level > logger_level)
4547 {
4548 return;
4549 }
4550
4551 s32 channel_count = handle->channels[level].offset;
4552
4553 if(channel_count < 0) /* it's count-1 actually */
4554 {
4555 return;
4556 }
4557
4558 logger_message* message = logger_message_alloc();
4559
4560 #if HAS_SHARED_QUEUE_SUPPORT
4561 message->pid = getpid_ex();
4562 #endif
4563 message->type = LOGGER_MESSAGE_TYPE_TEXT;
4564 message->text.level = level;
4565 message->text.flags = flags;
4566
4567 message->text.text_length = text_len;
4568 message->text.text_buffer_length = text_len;
4569
4570 message->text.handle = handle;
4571
4572 ZALLOC_ARRAY_OR_DIE(u8*, message->text.text, text_len, LOGRTEXT_TAG);
4573 memcpy(message->text.text, text, text_len);
4574
4575 #if SIZEOF_TIMEVAL <= 8
4576 gettimeofday(&message->text.tv, NULL);
4577 #else
4578 message->text.timestamp = timeus();
4579 #endif
4580
4581 message->text.prefix = (const u8*)prefix;
4582 message->text.prefix_length = prefix_len;
4583
4584 #if !HAS_SHARED_QUEUE_SUPPORT
4585 message->text.rc = 0;
4586
4587 #if DEBUG || HAS_LOG_PID
4588 message->text.pid = getpid_ex();
4589 #endif
4590 #endif
4591
4592 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4593 message->text.thread_id = thread_self();
4594 #endif
4595
4596 logger_message_post(message);
4597
4598 if(level <= exit_level)
4599 {
4600 logger_handle_trigger_emergency_shutdown();
4601 }
4602 }
4603
4604 void
logger_handle_try_msg(logger_handle * handle,u32 level,const char * fmt,...)4605 logger_handle_try_msg(logger_handle* handle, u32 level, const char* fmt, ...)
4606 {
4607 /*
4608 * check that the handle has got a channel for the level
4609 */
4610
4611 #if DEBUG
4612 if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4613 {
4614 #if DEBUG_LOG_HANDLER
4615 debug_stacktrace_print(termout, debug_stacktrace_get());
4616 debug_stacktrace_print(termerr, debug_stacktrace_get());
4617 flushout();
4618 flusherr();
4619 #endif
4620 abort();
4621 }
4622
4623 if(level >= MSG_LEVEL_COUNT)
4624 {
4625 debug_osformatln(termerr, "bad message level %u", level);
4626 logger_handle_trigger_emergency_shutdown();
4627 return;
4628 }
4629
4630 if(level <= MSG_ERR)
4631 {
4632 sleep(0);
4633 }
4634
4635 #endif
4636
4637 if(handle == NULL)
4638 {
4639 if(level <= exit_level)
4640 {
4641 logger_handle_trigger_emergency_shutdown();
4642 }
4643 return;
4644 }
4645
4646 if(level > logger_level)
4647 {
4648 return;
4649 }
4650
4651 s32 channel_count = handle->channels[level].offset;
4652
4653 if(channel_count < 0) /* it's count-1 actually */
4654 {
4655 return;
4656 }
4657
4658 logger_message* message = logger_message_try_alloc();
4659
4660 if(message == NULL)
4661 {
4662 return;
4663 }
4664
4665 /**
4666 * @note At this point we KNOW we have to print something.
4667 */
4668
4669 output_stream baos;
4670 #if HAS_SHARED_QUEUE_SUPPORT
4671 shared_heap_output_stream_context baos_context;
4672 #else
4673 bytezarray_output_stream_context baos_context;
4674 #endif
4675
4676 /*
4677 * DEFAULT_MAX_LINE_SIZE is the base size.
4678 *
4679 * The output stream has the BYTEARRAY_DYNAMIC flag set in order to allow
4680 * bigger sentences.
4681 *
4682 */
4683
4684 va_list args;
4685 va_start(args, fmt);
4686
4687 /* Will use the tmp buffer, but alloc a bigger one if required. */
4688 #if HAS_SHARED_QUEUE_SUPPORT
4689 shared_heap_output_stream_init_ex_static(&baos, logger_shared_heap_id, NULL, DEFAULT_MAX_LINE_SIZE, SHARED_HEAP_DYNAMIC, &baos_context);
4690 #else
4691 bytezarray_output_stream_init_ex_static(&baos, NULL, DEFAULT_MAX_LINE_SIZE, BYTEARRAY_DYNAMIC, &baos_context);
4692 #endif
4693
4694 if(FAIL(vosformat(&baos, fmt, args)))
4695 {
4696 #if HAS_SHARED_QUEUE_SUPPORT
4697 shared_heap_output_stream_reset(&baos);
4698 #else
4699 bytezarray_output_stream_reset(&baos);
4700 #endif
4701 osprint(&baos, "*** ERROR : MESSAGE FORMATTING FAILED ***");
4702 }
4703
4704 output_stream_write_u8(&baos, 0);
4705
4706 #if HAS_SHARED_QUEUE_SUPPORT
4707 message->pid = getpid_ex();
4708 #endif
4709 message->type = LOGGER_MESSAGE_TYPE_TEXT;
4710 message->text.level = level;
4711 message->text.flags = 0;
4712
4713 #if HAS_SHARED_QUEUE_SUPPORT
4714 message->text.text_length = shared_heap_output_stream_size(&baos) - 1;
4715 message->text.text_buffer_length = shared_heap_output_stream_buffer_size(&baos);
4716 #else
4717 message->text.text_length = bytezarray_output_stream_size(&baos) - 1;
4718 message->text.text_buffer_length = bytezarray_output_stream_buffer_size(&baos);
4719 #endif
4720
4721 message->text.handle = handle;
4722
4723 #if HAS_SHARED_QUEUE_SUPPORT
4724 message->text.text = shared_heap_output_stream_detach(&baos);
4725 #else
4726 message->text.text = bytezarray_output_stream_detach(&baos);
4727 #endif
4728
4729 assert(message->text.text != NULL);
4730
4731 #if SIZEOF_TIMEVAL <= 8
4732 gettimeofday(&message->text.tv, NULL);
4733 #else
4734 message->text.timestamp = timeus();
4735 #endif
4736
4737 // prefix
4738 // prefix_len
4739
4740 #if !HAS_SHARED_QUEUE_SUPPORT
4741 message->text.rc = 0;
4742
4743 #if DEBUG || HAS_LOG_PID
4744 message->text.pid = getpid_ex();
4745 #endif
4746 #endif
4747
4748 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4749 message->text.thread_id = thread_self();
4750 #endif
4751
4752 #if HAS_SHARED_QUEUE_SUPPORT
4753 logger_message_post(message);
4754 #else
4755 if(!threaded_queue_try_enqueue(&logger_commit_queue, message))
4756 {
4757 // could not enqueue
4758 ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
4759 logger_message_free(message);
4760 }
4761 #endif
4762
4763 va_end(args);
4764
4765 output_stream_close(&baos); /* Frees the memory */
4766
4767 if(level <= exit_level)
4768 {
4769 exit_level = 0;
4770 if(!dnscore_shuttingdown())
4771 {
4772 logger_handle_trigger_emergency_shutdown();
4773 }
4774 }
4775 }
4776
4777 void
logger_handle_try_msg_text(logger_handle * handle,u32 level,const char * text,u32 text_len)4778 logger_handle_try_msg_text(logger_handle* handle, u32 level, const char* text, u32 text_len)
4779 {
4780 /*
4781 * check that the handle has got a channel for the level
4782 */
4783
4784 #if DEBUG
4785 if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4786 {
4787 #if DEBUG_LOG_HANDLER
4788 debug_stacktrace_print(termout, debug_stacktrace_get());
4789 debug_stacktrace_print(termerr, debug_stacktrace_get());
4790 flushout();
4791 flusherr();
4792 #endif
4793 abort();
4794 }
4795
4796 if(level >= MSG_LEVEL_COUNT)
4797 {
4798 debug_osformatln(termerr, "bad message level %u", level);
4799 logger_handle_trigger_emergency_shutdown();
4800 return;
4801 }
4802
4803 if(level <= MSG_ERR)
4804 {
4805 sleep(0);
4806 }
4807
4808 #endif
4809
4810 if(handle == NULL)
4811 {
4812 if(level <= exit_level)
4813 {
4814 logger_handle_trigger_emergency_shutdown();
4815 }
4816 return;
4817 }
4818
4819 if(level > logger_level)
4820 {
4821 return;
4822 }
4823
4824 s32 channel_count = handle->channels[level].offset;
4825
4826 if(channel_count < 0) /* it's count-1 actually */
4827 {
4828 return;
4829 }
4830
4831 #if HAS_SHARED_QUEUE_SUPPORT
4832 logger_message* message = logger_message_try_alloc();
4833 #else
4834 logger_message* message = logger_message_alloc();
4835 #endif
4836
4837 #if HAS_SHARED_QUEUE_SUPPORT
4838 message->pid = getpid_ex();
4839 #endif
4840 message->type = LOGGER_MESSAGE_TYPE_TEXT;
4841 message->text.level = level;
4842 message->text.flags = 0;
4843
4844 message->text.text_length = text_len;
4845 message->text.text_buffer_length = text_len;
4846 message->text.handle = handle;
4847
4848 #if HAS_SHARED_QUEUE_SUPPORT
4849 message->text.text = (u8*)shared_heap_wait_alloc(logger_shared_heap_id, text_len);
4850 #else
4851 ZALLOC_ARRAY_OR_DIE(u8*, message->text.text, text_len, LOGRTEXT_TAG);
4852 #endif
4853
4854 assert(message->text.text != NULL);
4855
4856 memcpy(message->text.text, text, text_len);
4857
4858 #if SIZEOF_TIMEVAL <= 8
4859 gettimeofday(&message->text.tv, NULL);
4860 #else
4861 message->text.timestamp = timeus();
4862 #endif
4863
4864 // prefix
4865 // prefix_len
4866
4867 #if !HAS_SHARED_QUEUE_SUPPORT
4868 message->text.rc = 0;
4869
4870 #if DEBUG || HAS_LOG_PID
4871 message->text.pid = getpid_ex();
4872 #endif
4873 #endif
4874
4875 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4876 message->text.thread_id = thread_self();
4877 #endif
4878
4879 #if HAS_SHARED_QUEUE_SUPPORT
4880 logger_message_post(message);
4881 #else
4882 if(!threaded_queue_try_enqueue(&logger_commit_queue, message))
4883 {
4884 // could not enqueue
4885 ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
4886 logger_message_free(message);
4887 }
4888 #endif
4889
4890 if(level <= exit_level)
4891 {
4892 logger_handle_trigger_emergency_shutdown();
4893 }
4894 }
4895
4896 bool
logger_queue_fill_critical()4897 logger_queue_fill_critical()
4898 {
4899 #if HAS_SHARED_QUEUE_SUPPORT
4900 int size = shared_circular_buffer_size(logger_shared_queue);
4901 int room = shared_circular_buffer_avail(logger_shared_queue);
4902 #else
4903 int size = threaded_ringbuffer_cw_size(&logger_commit_queue);
4904 int room = threaded_ringbuffer_cw_room(&logger_commit_queue);
4905 #endif
4906 int maxsize = size + room;
4907 if(maxsize > 0)
4908 {
4909 float ratio = ((float)size) / ((float)maxsize);
4910
4911 return (ratio > 0.5f);
4912 }
4913 else
4914 {
4915 return TRUE;
4916 }
4917 }
4918
4919 static const char LOGGER_PATH_DEFAULT[] = "";
4920 static const char *g_logger_path = LOGGER_PATH_DEFAULT;
4921 static uid_t g_logger_uid = 0;
4922 static gid_t g_logger_gid = 0;
4923
4924 void
logger_set_path(const char * path)4925 logger_set_path(const char *path)
4926 {
4927 if(g_logger_path != LOGGER_PATH_DEFAULT)
4928 {
4929 free((char*)g_logger_path);
4930 }
4931 if(path != NULL)
4932 {
4933 g_logger_path = strdup(path);
4934 }
4935 else
4936 {
4937 g_logger_path = LOGGER_PATH_DEFAULT;
4938 }
4939 }
4940
4941 void
logger_release_ownership()4942 logger_release_ownership()
4943 {
4944 if(logger_thread_pid != -1)
4945 {
4946 logger_thread_pid = -1;
4947 }
4948
4949 if(logger_handle_owner_pid != -1)
4950 {
4951 logger_handle_owner_pid = -1;
4952 }
4953 }
4954
4955 void
logger_take_ownership(pid_t new_owner)4956 logger_take_ownership(pid_t new_owner)
4957 {
4958 if(logger_thread_pid == -1)
4959 {
4960 logger_thread_pid = new_owner;
4961 }
4962
4963 if(logger_handle_owner_pid == -1)
4964 {
4965 logger_handle_owner_pid = new_owner;
4966 }
4967 }
4968
4969 const char*
logger_get_path()4970 logger_get_path()
4971 {
4972 return g_logger_path;
4973 }
4974
4975 void
logger_set_uid(uid_t uid)4976 logger_set_uid(uid_t uid)
4977 {
4978 g_logger_uid = uid;
4979 }
4980
4981 uid_t
logger_get_uid()4982 logger_get_uid()
4983 {
4984 return g_logger_uid;
4985 }
4986
4987 void
logger_set_gid(uid_t gid)4988 logger_set_gid(uid_t gid)
4989 {
4990 g_logger_gid = gid;
4991 }
4992
4993 gid_t
logger_get_gid()4994 logger_get_gid()
4995 {
4996 return g_logger_gid;
4997 }
4998
4999 void
logger_set_level(u8 level)5000 logger_set_level(u8 level)
5001 {
5002 logger_level = MIN(level, MSG_ALL);
5003 }
5004
5005 bool
logger_wait_started()5006 logger_wait_started()
5007 {
5008 for(int countdown = 50; countdown > 0; --countdown)
5009 {
5010 int value = smp_int_get(&logger_thread_state);
5011 if(value == LOGGER_DISPATCHED_THREAD_STARTED)
5012 {
5013 return TRUE;
5014 }
5015 usleep_ex(100000);
5016 }
5017
5018 return FALSE;
5019 }
5020
5021 /** @} */
5022