NCBI C++ ToolKit
ncbi_c_log.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_c_log.c 100989 2023-10-12 15:10:57Z ivanov $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Vladimir Ivanov
27  *
28  * File Description:
29  * The C library to provide C++ Toolkit-like logging semantics
30  * and output for C/C++ programs and CGIs.
31  *
32  */
33 
34 
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include "ncbi_c_log_p.h"
38 
39 #if defined(NCBI_OS_UNIX)
40 # include <string.h>
41 # include <limits.h>
42 # include <ctype.h>
43 # include <unistd.h>
44 # include <sys/utsname.h>
45 # include <sys/time.h>
46 # include <sys/types.h>
47 # if !defined(__CYGWIN__)
48 # include <sys/syscall.h>
49 # endif
50 # include <fcntl.h> /* for open() constants */
51 # include <sys/errno.h>
52 
53 #elif defined(NCBI_OS_MSWIN)
54 # include <sys/types.h>
55 # include <sys/timeb.h>
56 # include <windows.h>
57 # include <direct.h>
58 #endif
59 
60 #if defined(_MT)
61 # if defined(NCBI_OS_MSWIN)
62 # define NCBI_WIN32_THREADS
63 # elif defined(NCBI_OS_UNIX)
64 # define NCBI_POSIX_THREADS
65 # else
66 # define NCBI_NO_THREADS
67 # endif
68 #else
69 # define NCBI_NO_THREADS
70 #endif
71 
72 #if defined(NCBI_POSIX_THREADS)
73 # include <pthread.h>
74 #endif
75 
76 /* assert, verify */
77 #if !defined(NDEBUG) && !defined(_DEBUG)
78 # define NDEBUG
79 #endif
80 
81 #include <assert.h>
82 
83 /* Critical error, unrecoverable. Should never happen */
84 #ifdef TROUBLE
85 # undef TROUBLE
86 #endif
87 #define TROUBLE s_Abort(__LINE__, 0)
88 #define TROUBLE_MSG(msg) s_Abort(__LINE__, msg)
89 
90 /* Macro to catch a minor errors on a debugging stage.
91  * The code it checks can fails theoretically in release mode, but should not be fatal.
92  * See also VERIFY for verifying fatal errors.
93  */
94 #if defined(NDEBUG)
95 # define verify(expr) while ( expr ) break
96 #else
97 # define verify(expr) assert(expr)
98 #endif
99 
100 /* Verify an expression.
101  * Debug modes - abort on error.
102  * Release modes - report an error if specified (to stderr), continue execution.
103  */
104 #ifdef VERIFY
105 # undef VERIFY
106 #endif
107 
108 #if defined(NDEBUG)
109 # define VERIFY(expr) do { if ( !(expr) ) s_ReportError(__LINE__, #expr); } while ( 0 )
110 #else
111 # define VERIFY(expr) do { if ( !(expr) ) s_Abort(__LINE__, #expr); s_ReportError(__LINE__, #expr); } while ( 0 )
112 #endif
113 
114 #if defined(NDEBUG)
115 # define VERIFY_CATCH(expr) do { if ( !(expr) ) { s_ReportError(__LINE__, #expr); goto __catch_error; } } while ( 0 )
116 #else
117 # define VERIFY_CATCH(expr) do { if ( !(expr) ) { s_Abort(__LINE__, #expr); goto __catch_error; } } while ( 0 )
118 #endif
119 
120 /* Catch errors from VERIFY_CATCH.
121  * @example
122  * // some yours code with verifying errors
123  * VERIFY(non-critical expression);
124  * VERIFY_CATCH(critical expression);
125  * // and normal return
126  * return;
127  * CATCH:
128  * // recovery code
129  * return;
130  */
131 #define CATCH __catch_error
132 
133 #if defined(__GNUC__)
134 # define UNUSED_ARG(x) x##_UNUSED __attribute__((unused))
135 #else
136 # define UNUSED_ARG(x) x##_UNUSED
137 #endif
138 
139 /* min() */
140 #define min_value(a,b) ((a) < (b) ? (a) : (b))
141 
142 /* Directory separator */
143 #if defined(NCBI_OS_MSWIN)
144 # define DIR_SEPARATOR '\\'
145 #elif defined(NCBI_OS_UNIX)
146 # define DIR_SEPARATOR '/'
147 #endif
148 
149 
150 
151 /******************************************************************************
152  * Configurables that could theoretically change
153  */
154 
155 #define UNKNOWN_HOST "UNK_HOST"
156 #define UNKNOWN_CLIENT "UNK_CLIENT"
157 #define UNKNOWN_SESSION "UNK_SESSION"
158 #define UNKNOWN_HITID ""
159 #define UNKNOWN_APPNAME "UNK_APP"
160 
161 
162 /*****************************************************************************
163  * Global constants
164  */
165 
166 static const char* kBaseLogDir = "/log/";
167 
168 
169 
170 /*****************************************************************************
171  * Global variables
172  */
173 
174 /* Init is done if TRUE */
175 static volatile int /*bool*/ sx_IsInit = 0;
176 
177 /* Enable/disable logging */
178 static volatile int /*bool*/ sx_IsEnabled = 0;
179 
180 /* Enable/disable checks and state verifications -- used in ncbi_applog utility */
181 static volatile int /*bool*/ sx_DisableChecks = 0;
182 
183 /* Application access log and error postings info structure (global) */
184 static volatile TNcbiLog_Info* sx_Info = NULL;
185 
186 /* Pointer to the context (single-threaded applications only, otherwise use TLS) */
188 
189 /* Real PID for the main thread */
190 static volatile TNcbiLog_PID sx_PID = 0;
191 
192 
193 /******************************************************************************
194  * Abort (for the locally defined VERIFY and TROUBLE macros)
195  */
196 
197 static void s_Abort(long line, const char* msg)
198 {
199  /* Check environment variable for silent exit */
200  char* v = getenv("DIAG_SILENT_ABORT");
201 
202  if (msg && *msg) {
203  fprintf(stderr, "Critical error: %s, %s, line %ld\n", msg, __FILE__, line);
204  } else {
205  fprintf(stderr, "Critical error at %s, line %ld\n", __FILE__, line);
206  }
207  if (v && (*v == 'Y' || *v == 'y' || *v == '1')) {
208  exit(255);
209  }
210  if (v && (*v == 'N' || *v == 'n' || *v == '0')) {
211  abort();
212  }
213 
214 #if defined(_DEBUG)
215  abort();
216 #else
217  exit(255);
218 #endif
219 }
220 
221 
222 /******************************************************************************
223  * CLog error reporting (for the locally defined VERIFY)
224  * Used for debugging release binaries only.
225  * Do nothing if CLog reporting destination is set to eNcbiLog_Stderr.
226 */
227 
228 static void s_ReportError(long line, const char* msg)
229 {
231  return;
232  }
233  char* v = getenv("NCBI_CLOG_REPORT_ERRORS");
234  if (!v || !(*v == 'Y' || *v == 'y' || *v == '1')) {
235  return;
236  }
237  /* Report error */
238  const char* m = (msg && *msg) ? msg : "unknown";
239  fprintf(stderr, "\nCLog error: %s, %s, line %ld\n", m, __FILE__, line);
240 }
241 
242 
243 /******************************************************************************
244  * MT locking
245  */
246 
247 /* Define default MT handler */
248 
249 #if defined(NCBI_POSIX_THREADS)
250  static pthread_mutex_t sx_MT_handle = PTHREAD_MUTEX_INITIALIZER;
251 #elif defined(NCBI_WIN32_THREADS)
252  static CRITICAL_SECTION sx_MT_handle;
253 #endif
254 
256  (void* UNUSED_ARG(user_data),
258  )
259 {
260 #if defined(NCBI_POSIX_THREADS)
261  switch (action) {
262  case eNcbiLog_MT_Init:
263  /* Already done with static initialization; do nothing here */
264  /* verify(pthread_mutex_init(&sx_MT_handle, 0) == 0); */
265  break;
266  case eNcbiLog_MT_Destroy:
267  /* Mutex should be unlocked before destroying */
268  assert(pthread_mutex_unlock(&sx_MT_handle) == 0);
269  verify(pthread_mutex_destroy(&sx_MT_handle) == 0);
270  break;
271  case eNcbiLog_MT_Lock:
272  verify(pthread_mutex_lock(&sx_MT_handle) == 0);
273  break;
274  case eNcbiLog_MT_Unlock:
275  verify(pthread_mutex_unlock(&sx_MT_handle) == 0);
276  break;
277  }
278  return 1;
279 
280 #elif defined(NCBI_WIN32_THREADS)
281 
282  switch (action) {
283  case eNcbiLog_MT_Init:
284  InitializeCriticalSection(&sx_MT_handle);
285  break;
286  case eNcbiLog_MT_Destroy:
287  DeleteCriticalSection(&sx_MT_handle);
288  break;
289  case eNcbiLog_MT_Lock:
290  EnterCriticalSection(&sx_MT_handle);
291  break;
292  case eNcbiLog_MT_Unlock:
293  LeaveCriticalSection(&sx_MT_handle);
294  break;
295  }
296  return 1;
297 
298 #else
299  /* Not implemented -- not an MT build or current platform
300  doesn't support MT-threading */
301  return 0;
302 #endif
303 }
304 
305 
306 /* MT locker data and callbacks */
308  void* user_data; /**< For "handler()" */
309  FNcbiLog_MTLock_Handler handler; /**< Handler function */
310  unsigned int magic_number; /**< Used internally to make sure it's init'd */
311 };
312 #define kMTLock_magic_number 0x4C0E681F
313 
314 
315 /* Always use default MT lock by default; can be redefined/disabled by NcbiLog_Init() */
316 #if defined(_MT)
319 #else
320 static volatile TNcbiLog_MTLock sx_MTLock = NULL;
321 #endif
322 /* We don't need to destroy default MT lock */
323 static volatile int /*bool*/ sx_MTLock_Own = 0;
324 
325 
326 /* Check the validity of the MT locker */
327 #define MT_LOCK_VALID \
328  if (sx_MTLock) assert(sx_MTLock->magic_number == kMTLock_magic_number)
329 
330 static int/*bool*/ s_MTLock_Do(ENcbiLog_MTLock_Action action)
331 {
334  : -1 /* rightful non-doing */;
335 }
336 
337 #define MT_LOCK_Do(action) (sx_MTLock ? s_MTLock_Do((action)) : -1)
338 
339 /* Init/Lock/unlock/destroy the MT logger lock
340  */
341 #define MT_INIT verify(MT_LOCK_Do(eNcbiLog_MT_Init) != 0)
342 #define MT_LOCK verify(MT_LOCK_Do(eNcbiLog_MT_Lock) != 0)
343 #define MT_UNLOCK verify(MT_LOCK_Do(eNcbiLog_MT_Unlock) != 0)
344 #define MT_DESTROY verify(MT_LOCK_Do(eNcbiLog_MT_Destroy) != 0)
345 
346 
348  (void* user_data,
350  )
351 {
352  TNcbiLog_MTLock lock = (struct TNcbiLog_MTLock_tag*)
353  malloc(sizeof(struct TNcbiLog_MTLock_tag));
354  if (lock) {
355  lock->user_data = user_data;
356  lock->handler = handler;
358  }
359  return lock;
360 }
361 
362 
364 {
365  if (lock) {
367  MT_DESTROY;
368  lock->magic_number = 0;
369  free(lock);
370  lock = NULL;
371  }
372 }
373 
374 
375 
376 /******************************************************************************
377  * Thread-local storage (TLS)
378  */
379 
380 /* Init is done for TLS */
381 static volatile int /*bool*/ sx_TlsIsInit = 0;
382 
383 /* Platform-specific TLS key */
384 #if defined(NCBI_POSIX_THREADS)
385  static volatile pthread_key_t sx_Tls;
386 #elif defined(NCBI_WIN32_THREADS)
387  static volatile DWORD sx_Tls;
388 #endif
389 
390 
391 static void s_TlsInit(void)
392 {
394  /* Create platform-dependent TLS key (index) */
395 #if defined(NCBI_POSIX_THREADS)
396  verify(pthread_key_create((pthread_key_t*)&sx_Tls, NULL) == 0);
397  /* pthread_key_create does not reset the value to 0 if the key */
398  /* has been used and deleted. */
399  verify(pthread_setspecific(sx_Tls, 0) == 0);
400  sx_TlsIsInit = 1;
401 #elif defined(NCBI_WIN32_THREADS)
402  sx_Tls = TlsAlloc();
403  verify(sx_Tls != TLS_OUT_OF_INDEXES);
404  sx_TlsIsInit = 1 /*true*/;
405 #else
406  /* Do not use TLS */
407 #endif
408 }
409 
410 
411 static void s_TlsDestroy(void)
412 {
414 #if defined(NCBI_POSIX_THREADS)
415  verify(pthread_key_delete(sx_Tls) == 0);
416 #elif defined(NCBI_WIN32_THREADS)
417  TlsFree(sx_Tls);
418 #else
419  TROUBLE;
420 #endif
421  sx_TlsIsInit = 0 /*false*/;
422 }
423 
424 
425 static void* s_TlsGetValue(void)
426 {
427  void* ptr = NULL;
429 #if defined(NCBI_POSIX_THREADS)
430  ptr = pthread_getspecific(sx_Tls);
431 #elif defined(NCBI_WIN32_THREADS)
432  ptr = TlsGetValue(sx_Tls);
433  if (!ptr) {
434  assert(GetLastError() == ERROR_SUCCESS);
435  }
436 #else
437  TROUBLE;
438 #endif
439  return ptr;
440 }
441 
442 
443 static void s_TlsSetValue(void* ptr)
444 {
446 #if defined(NCBI_POSIX_THREADS)
447  verify(pthread_setspecific(sx_Tls, ptr) == 0);
448 #elif defined(NCBI_WIN32_THREADS)
449  verify(TlsSetValue(sx_Tls, ptr));
450 #else
451  TROUBLE;
452 #endif
453 }
454 
455 
456 
457 /******************************************************************************
458  * Useful macro
459  */
460 
461 /* Check initialization and acquire MT lock */
462 #define MT_LOCK_API \
463  assert(sx_IsInit); \
464  while (!sx_IsEnabled) { \
465  /* Delays is possible only on the time of first Init() */ \
466  s_SleepMicroSec(10); \
467  } \
468  assert(sx_Info); \
469  MT_LOCK
470 
471 
472 /* Print application start message, if not done yet */
473 static void s_AppStart(TNcbiLog_Context ctx, const char* argv[]);
474 #define CHECK_APP_START(ctx) \
475  if (sx_Info->state == eNcbiLog_NotSet) { \
476  s_AppStart(ctx, NULL); \
477  }
478 
479 /* Forward declaration */
480 static void s_Extra(TNcbiLog_Context ctx, const SNcbiLog_Param* params);
481 static void s_ExtraStr(TNcbiLog_Context ctx, const char* params);
482 
483 
484 
485 /******************************************************************************
486  * Aux. functions
487  */
488 
489 
490 /** Sleep the specified number of microseconds.
491  Portable and ugly. But we don't need more precision version here,
492  we will use it only for context switches and avoiding possible CPU load.
493  */
494 void s_SleepMicroSec(unsigned long mc_sec)
495 {
496 #if defined(NCBI_OS_MSWIN)
497  Sleep((mc_sec + 500) / 1000);
498 #elif defined(NCBI_OS_UNIX)
499  struct timeval delay;
500  delay.tv_sec = (long)(mc_sec / 1000000);
501  #if defined(NCBI_OS_DARWIN)
502  delay.tv_usec = (int)(mc_sec % 1000000);
503  #else
504  delay.tv_usec = (long)(mc_sec % 1000000);
505  #endif
506  while (select(0, (fd_set*) 0, (fd_set*) 0, (fd_set*) 0, &delay) < 0) {
507  break;
508  }
509 #endif
510 }
511 
512 
513 /** strdup() doesn't exists on all platforms, and we cannot check this here.
514  Will use our own implementation.
515  */
516 static char* s_StrDup(const char* str)
517 {
518  size_t size = strlen(str) + 1;
519  char* res = (char*) malloc(size);
520  if (res) {
521  memcpy(res, str, size);
522  }
523  return res;
524 }
525 
526 
527 /** Concatenate two parts of the path for the current OS.
528  */
529 static const char* s_ConcatPathEx(
530  const char* p1, size_t p1_len, /* [in] non-NULL */
531  const char* p2, size_t p2_len, /* [in] non-NULL */
532  char* dst, /* [in/out] non-NULL */
533  size_t dst_size /* [in] */
534 )
535 {
536  size_t n = 0;
537  assert(p1);
538  assert(p2);
539  assert(dst);
540  assert(dst_size);
541 
542  if (p1_len + p2_len + 2 >= dst_size) {
543  return NULL;
544  }
545  memcpy(dst, p1, p1_len);
546  n += p1_len;
547  if (dst[n-1] != DIR_SEPARATOR) {
548  dst[n++] = DIR_SEPARATOR;
549  }
550  memcpy(dst + n, p2, p2_len);
551  n += p2_len;
552  dst[n] = '\0';
553  return dst;
554 }
555 
556 
557 /** Concatenate two parts of the path (zero-terminated strings) for the current OS.
558  */
559 static const char* s_ConcatPath(
560  const char* p1, /* [in] non-NULL */
561  const char* p2, /* [in] non-NULL */
562  char* dst, /* [in/out] non-NULL */
563  size_t dst_size /* [in] */
564 )
565 {
566  return s_ConcatPathEx(p1, strlen(p1), p2, strlen(p2), dst, dst_size);
567 }
568 
569 
570 /** Get host name.
571  * The order is: cached host name, $NCBI_HOST, uname() or COMPUTERNAME, empty string.
572  */
573 const char* NcbiLog_GetHostName(void)
574 {
575  static const char* host = NULL;
576  const char* p;
577 #if defined(NCBI_OS_UNIX)
578  struct utsname buf;
579 #endif
580  if ( host ) {
581  return host;
582  }
583  if ( (p = getenv("NCBI_HOST")) != NULL && *p ) {
584  host = s_StrDup(p);
585  return host;
586  }
587 #if defined(NCBI_OS_UNIX)
588  if (uname(&buf) == 0) {
589  host = s_StrDup(buf.nodename);
590  }
591 #elif defined(NCBI_OS_MSWIN)
592  /* MSWIN - use COMPUTERNAME */
593  if ( (p = getenv("COMPUTERNAME")) != NULL && *p ) {
594  host = s_StrDup(p);
595  }
596 #endif
597  return host;
598 }
599 
600 
601 /** Read first string from specified file.
602  * Return NULL on error.
603  */
604 static const char* s_ReadFileString(const char* filename)
605 {
606  FILE* fp;
607  char buf[32];
608  size_t len = sizeof(buf);
609  char* p = buf;
610 
611  fp = fopen(filename, "rt");
612  if (!fp) {
613  return NULL;
614  }
615  if (fgets(buf, (int)len, fp) == NULL) {
616  fclose(fp);
617  return NULL;
618  }
619  fclose(fp);
620 
621  /* Removing trailing spaces and following EOL */
622  while (*p && !(*p == ' ' || *p == '\n')) p++;
623  *p = '\0';
624  return s_StrDup(buf);
625 }
626 
627 
628 /** Get host role string.
629  */
630 const char* NcbiLog_GetHostRole(void)
631 {
632  static const char* role = NULL;
633  const char* p = NULL;
634  if ( role ) {
635  return role;
636  }
637  if ( (p = getenv("NCBI_ROLE")) != NULL && *p ) {
638  role = s_StrDup(p);
639  return role;
640  }
641  role = s_ReadFileString("/etc/ncbi/role");
642  return role;
643 }
644 
645 
646 /** Get host location string.
647  */
648 const char* NcbiLog_GetHostLocation(void)
649 {
650  static const char* location = NULL;
651  const char* p = NULL;
652  if ( location ) {
653  return location;
654  }
655  if ( (p = getenv("NCBI_LOCATION")) != NULL && *p ) {
656  location = s_StrDup(p);
657  return location;
658  }
659  location = s_ReadFileString("/etc/ncbi/location");
660  return location;
661 }
662 
663 
664 /** Get current process ID.
665 */
666 static TNcbiLog_PID s_GetPID(void)
667 {
668  /* For main thread always force caching of PIDs */
669  if ( !sx_PID ) {
670 #if defined(NCBI_OS_UNIX)
671  sx_PID = (TNcbiLog_PID)getpid();
672 #elif defined(NCBI_OS_MSWIN)
673  sx_PID = GetCurrentProcessId();
674 #endif
675  }
676  return sx_PID;
677 }
678 
679 
680 /** Get current thread ID.
681  */
682 static TNcbiLog_TID s_GetTID(void)
683 {
684  /* Never cache thread ID */
685  TNcbiLog_TID tid = 0;
686 #if defined(NCBI_NO_THREADS)
687  tid = 0;
688 #elif defined(NCBI_OS_UNIX)
689 # if defined(SYS_gettid)
690  tid = (TNcbiLog_TID)syscall(SYS_gettid); /* NCBI_FAKE_WARNING: Clang */
691 # else
692  // pthread_self() function returns the pthread handle of the calling thread.
693  // On Mac OS X >= 10.6 and iOS >= 3.2 non-portable pthread_getthreadid_np()
694  // can be used to return an integral identifier for the thread,
695  // but pthread_self() is good enough for our needs and portable.
696  tid = (TNcbiLog_TID)pthread_self(); /* NCBI_FAKE_WARNING */
697 # endif
698 #elif defined(NCBI_OS_MSWIN)
699  tid = GetCurrentThreadId();
700 #endif
701  return tid;
702 }
703 
704 
705 /** Create unique process ID.
706  * Adapted from C++ Toolkit code: see CDiagContect::x_CreateUID().
707  */
709 {
710  TNcbiLog_PID pid = s_GetPID();
711  TNcbiLog_UInt8 t = (TNcbiLog_UInt8)time(0);
712  const char* host = NcbiLog_GetHostName();
713  const char* s;
714  TNcbiLog_UInt8 h = 212;
715 
716  /* Use host name */
717  if ( host ) {
718  for (s = host; *s != '\0'; s++) {
719  h = h*1265 + (unsigned char)(*s);
720  }
721  }
722  h &= 0xFFFF;
723  /* The low 4 bits are reserved as GUID generator version number.
724  We use version #3. Actually we use C++ version #1 algorithm here,
725  but assign new version number to distinguish the NCBI C logging API
726  from the C++ API.
727  */
728  return (h << 48) |
729  ((pid & 0xFFFF) << 32) |
730  ((t & 0xFFFFFFF) << 4) |
731  3;
732 }
733 
734 
735 /** Update current UID with new timestamp.
736  * This functions don't change global UID, just return a copy.
737  *
738  * -- not used at this moment, but can be usable later.
739  */
740 #if 0
741 static TNcbiLog_Int8 s_UpdateUID(void)
742 {
743  time_t t;
744  TNcbiLog_Int8 guid;
745  /* Update with current timestamp */
746  assert(sx_Info->guid);
747  guid = sx_Info->guid;
748  t = time(0);
749  /* Clear old timestamp */
750  guid &= ~((TNcbiLog_Int8)0xFFFFFFF << 4);
751  /* Add current timestamp */
752  guid |= (((TNcbiLog_Int8)t & 0xFFFFFFF) << 4);
753  return guid;
754 }
755 #endif
756 
757 
758 /** Get current GMT time with nanoseconds
759 */
760 static int/*bool*/ s_GetTimeT(time_t* time_sec, unsigned long* time_ns)
761 {
762 #if defined(NCBI_OS_MSWIN)
763  struct _timeb timebuffer;
764 #elif defined(NCBI_OS_UNIX)
765  struct timeval tp;
766 #endif
767  if (!time_sec || ! time_ns) {
768  return 0;
769  }
770 #if defined(NCBI_OS_MSWIN)
771  _ftime(&timebuffer);
772  *time_sec = timebuffer.time;
773  *time_ns = (long) timebuffer.millitm * 1000000;
774 
775 #elif defined(NCBI_OS_UNIX)
776  if (gettimeofday(&tp,0) != 0) {
777  *time_sec = -1;
778  } else {
779  *time_sec = tp.tv_sec;
780  *time_ns = (unsigned long)((double)tp.tv_usec * 1000);
781  }
782 #else
783  *time_sec = time(0);
784  *time_ns = 0;
785 #endif
786  if (*time_sec == (time_t)(-1)) {
787  return 0;
788  }
789  return 1;
790 }
791 
792 
793 /** Get current GMT time with nanoseconds (STime version)
794 */
795 static int/*bool*/ s_GetTime(STime* t)
796 {
797  if ( !t ) {
798  return 0;
799  }
800  return s_GetTimeT(&t->sec, &t->ns);
801 }
802 
803 
804 /** Get time difference, time_end >- time_start
805  */
806 static double s_DiffTime(const STime time_start, const STime time_end)
807 {
808  double ts;
809  ts = ((double)time_end.sec - (double)time_start.sec) +
810  ((double)time_end.ns - (double)time_start.ns)/1000000000;
811  return ts;
812 }
813 
814 
815 /** Get current local time in format 'YYYY-MM-DDThh:mm:ss.sss'
816  */
817 static int/*bool*/ s_GetTimeStr
818  (char* buf, /* [in/out] non-NULL, must fit 24 symbols */
819  time_t time_sec, /* [in] */
820  unsigned long time_ns /* [in] */
821  )
822 {
823 #ifdef HAVE_LOCALTIME_R
824  struct tm *temp;
825 #endif
826  struct tm *t;
827  int n;
828 
829  /* Get current time if necessary */
830  if ( !time_sec ) {
831  if (!s_GetTimeT(&time_sec, &time_ns)) {
832  return 0;
833  }
834  }
835 
836  /* Get local time */
837 #ifdef HAVE_LOCALTIME_R
838  localtime_r(&time_sec, &temp);
839  t = &temp;
840 #else
841  t = localtime(&time_sec);
842  if ( !t ) {
843  /* Error was detected: incorrect timer value or system error */
844  return 0;
845  }
846 #endif
847  /* YYYY-MM-DDThh:mm:ss.sss */
848  n = sprintf(buf, "%04u-%02u-%02uT%02u:%02u:%02u.%03u",
849  t->tm_year + 1900,
850  t->tm_mon + 1,
851  t->tm_mday,
852  t->tm_hour,
853  t->tm_min,
854  t->tm_sec,
855  (unsigned int)(time_ns / 1000000) /* truncate to 3 digits */
856  );
857  if (n != 23) {
858  return 0 /*false*/;
859  }
860  return 1 /*true*/;
861 }
862 
863 
864 /** This routine is called during start up and again in NcbiLog_ReqStart().
865  The received environment value will be cached for whole process.
866  */
867 static const char* s_GetClient_Env(void)
868 {
869  static const char* client = NULL;
870  int/*bool*/ internal, external;
871  const char* p;
872 
873  if ( client ) {
874  return client;
875  }
876  internal = (p = getenv("HTTP_CAF_INTERNAL")) != NULL && *p ? 1 : 0;
877  external = (((p = getenv("HTTP_CAF_EXTERNAL")) != NULL && *p) ||
878  ((p = getenv("HTTP_NCBI_EXTERNAL")) != NULL && *p)) ? 1 : 0;
879  if ( internal || !external ) {
880  if ( (p = getenv("HTTP_CLIENT_HOST")) != NULL && *p ) {
881  client = s_StrDup(p);
882  return client;
883  }
884  }
885  if ( (p = getenv("HTTP_CAF_PROXIED_HOST")) != NULL && *p ) {
886  client = s_StrDup(p);
887  return client;
888  }
889  if ( (p = getenv("PROXIED_IP")) != NULL && *p ) {
890  client = s_StrDup(p);
891  return client;
892  }
893  if ( (p = getenv("HTTP_X_REAL_IP")) != NULL && *p ) {
894  client = s_StrDup(p);
895  return client;
896  }
897  if ( (p = getenv("REMOTE_ADDR")) != NULL && *p ) {
898  client = s_StrDup(p);
899  return client;
900  }
901  return NULL;
902 }
903 
904 
905 /** This routine is called during start up and again in NcbiLog_ReqStart().
906  The received environment value will be cached for whole process.
907  */
908 extern const char* NcbiLogP_GetSessionID_Env(void)
909 {
910  static const char* session = NULL;
911  const char* p;
912 
913  if ( session ) {
914  return session;
915  }
916  if ( (p = getenv("HTTP_NCBI_SID")) != NULL && *p ) {
917  session = s_StrDup(p);
918  return session;
919  }
920  if ( (p = getenv("NCBI_LOG_SESSION_ID")) != NULL && *p ) {
921  session = s_StrDup(p);
922  return session;
923  }
924  return NULL;
925 }
926 
927 
928 /** This routine is called during start up and again in NcbiLog_ReqStart().
929  The received environment value will be cached for whole process.
930  */
931 extern const char* NcbiLogP_GetHitID_Env(void)
932 {
933  static const char* phid = NULL;
934  const char* p;
935 
936  if ( phid ) {
937  return phid;
938  }
939  if ( (p = getenv("HTTP_NCBI_PHID")) != NULL && *p ) {
940  phid = s_StrDup(p);
941  return phid;
942  }
943  if ( (p = getenv("NCBI_LOG_HIT_ID")) != NULL && *p ) {
944  phid = s_StrDup(p);
945  return phid;
946  }
947  return NULL;
948 }
949 
950 
951 /** Get value from numeric-based environment variables.
952  */
953 extern int NcbiLogP_GetEnv_UInt(const char* env_var_name, unsigned int* value)
954 {
955  const char* p;
956  if ( (p = getenv(env_var_name)) != NULL && *p ) {
957  char* e;
958  unsigned long v = strtoul(p, &e, 10);
959  if (v <= UINT_MAX && !*e) {
960  if (value) {
961  *value = (unsigned int)v;
962  }
963  return 0;
964  }
965  }
966  return -1;
967 }
968 
969 
970 
971 /* The URL-encoding table
972  */
973 static const unsigned char sx_EncodeTable[256][4] = {
974  "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
975  "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F",
976  "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
977  "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F",
978  "+", "!", "%22", "%23", "$", "%25", "%26", "'",
979  "(", ")", "*", "%2B", ",", "-", ".", "%2F",
980  "0", "1", "2", "3", "4", "5", "6", "7",
981  "8", "9", "%3A", "%3B", "%3C", "%3D", "%3E", "%3F",
982  "%40", "A", "B", "C", "D", "E", "F", "G",
983  "H", "I", "J", "K", "L", "M", "N", "O",
984  "P", "Q", "R", "S", "T", "U", "V", "W",
985  "X", "Y", "Z", "%5B", "%5C", "%5D", "%5E", "_",
986  "%60", "a", "b", "c", "d", "e", "f", "g",
987  "h", "i", "j", "k", "l", "m", "n", "o",
988  "p", "q", "r", "s", "t", "u", "v", "w",
989  "x", "y", "z", "%7B", "%7C", "%7D", "%7E", "%7F",
990  "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
991  "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F",
992  "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
993  "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
994  "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7",
995  "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF",
996  "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7",
997  "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF",
998  "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
999  "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF",
1000  "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7",
1001  "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF",
1002  "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7",
1003  "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
1004  "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7",
1005  "%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
1006 };
1007 
1008 /** URL-encode up to "src_size" symbols(bytes) from buffer "src_buf".
1009  * Write the encoded data to buffer "dst_buf", but no more than
1010  * "dst_size" bytes.
1011  * Assign "*src_read" to the # of bytes successfully encoded from "src_buf".
1012  * Assign "*dst_written" to the # of bytes written to buffer "dst_buf".
1013  */
1014 static void s_URL_Encode
1015  (const void* src_buf, /* [in] non-NULL */
1016  size_t src_size, /* [in] */
1017  size_t* src_read, /* [out] non-NULL */
1018  void* dst_buf, /* [in/out] non-NULL */
1019  size_t dst_size, /* [in] */
1020  size_t* dst_written /* [out] non-NULL */
1021  )
1022 {
1023  unsigned char* src = (unsigned char*) src_buf;
1024  unsigned char* dst = (unsigned char*) dst_buf;
1025 
1026  *src_read = 0;
1027  *dst_written = 0;
1028  if (!src_size || !dst_size || !dst || !src)
1029  return;
1030 
1031  for ( ; *src_read != src_size && *dst_written != dst_size;
1032  (*src_read)++, (*dst_written)++, src++, dst++)
1033  {
1034  const unsigned char* subst = sx_EncodeTable[*src];
1035  if (*subst != '%') {
1036  *dst = *subst;
1037  } else if (*dst_written < dst_size - 2) {
1038  *dst = '%';
1039  *(++dst) = *(++subst);
1040  *(++dst) = *(++subst);
1041  *dst_written += 2;
1042  } else {
1043  return;
1044  }
1045  }
1046 }
1047 
1048 
1049 #if 0
1050 -- not used.
1051 -- only s_EscapeNewlines() is used to escape newlines to applog format during printing messages.
1052 
1053 /** Get a printable version of the specified string.
1054  * All non-printable characters will be represented as "\r", "\n", "\v",
1055  * "\t", etc, or "\ooo" where 'ooo' is the octal code of the character.
1056  *
1057  * This function read up to "src_size" symbols(bytes) from buffer "src_buf".
1058  * Write the encoded data to buffer "dst_buf", but no more than "dst_size" bytes.
1059  * Assign "*src_read" to the # of bytes successfully encoded from "src_buf".
1060  * Assign "*dst_written" to the # of bytes written to buffer "dst_buf".
1061  */
1062 static void s_Sanitize
1063  (const void* src_buf, /* [in] non-NULL */
1064  size_t src_size, /* [in] */
1065  size_t* src_read, /* [out] non-NULL */
1066  void* dst_buf, /* [in/out] non-NULL */
1067  size_t dst_size, /* [in] */
1068  size_t* dst_written /* [out] non-NULL */
1069  )
1070 {
1071  unsigned char* src = (unsigned char*) src_buf;
1072  unsigned char* dst = (unsigned char*) dst_buf;
1073 
1074  *src_read = 0;
1075  *dst_written = 0;
1076  if (!src_size || !dst_size || !dst || !src)
1077  return;
1078 
1079  for ( ; *src_read != src_size && *dst_written != dst_size;
1080  (*src_read)++, src++, dst++)
1081  {
1082  unsigned char c = *src;
1083  unsigned char subst = 0;
1084 
1085  switch (c) {
1086  case '\n':
1087  subst = 'n'; break;
1088  case '\r':
1089  subst = 'r'; break;
1090  case '\t':
1091  subst = 't'; break;
1092  case '\v':
1093  subst = 'v'; break;
1094  case '\b':
1095  subst = 'b'; break;
1096  case '\f':
1097  subst = 'f'; break;
1098  case '\a':
1099  subst = 'a'; break;
1100  }
1101  if ( subst ) {
1102  if (*dst_written + 2 > dst_size) {
1103  break;
1104  }
1105  *dst = '\\';
1106  *(++dst) = subst;
1107  *dst_written += 2;
1108  } else if (isprint(c)) {
1109  *dst = c;
1110  *dst_written += 1;
1111  } else {
1112  /* convert to octal string */
1113  unsigned char v;
1114  if (*dst_written + 4 > dst_size) {
1115  break;
1116  }
1117  *dst = '\\';
1118  v = c >> 6;
1119  *(++dst) = (unsigned char)('0' + v);
1120  v = (c >> 3) & 7;
1121  *(++dst) = (unsigned char)('0' + v);
1122  v = c & 7;
1123  *(++dst) = (unsigned char)('0' + v);
1124 
1125  *dst_written += 4;
1126  }
1127  }
1128 }
1129 #endif
1130 
1131 
1132 /** Escape newlines in the string.
1133  *
1134  * Follow CXX-7439 applog standard newline replacement convention.
1135  * - \n -> \v
1136  * - \v -> 0xFF \v
1137  * - 0xFF -> 0xFF 0xFF
1138  *
1139  * This function read up to "src_size" symbols(bytes) from buffer "src_buf".
1140  * Write the escaped data to buffer "dst_buf", but no more than "dst_size" bytes.
1141  * Assign "*src_read" to the # of bytes successfully escaped from "src_buf".
1142  * Assign "*dst_written" to the # of bytes written to buffer "dst_buf".
1143  */
1144 static void s_EscapeNewlines
1145  (const void* src_buf, /* [in] non-NULL */
1146  size_t src_size, /* [in] */
1147  size_t* src_read, /* [out] non-NULL */
1148  void* dst_buf, /* [in/out] non-NULL */
1149  size_t dst_size, /* [in] */
1150  size_t* dst_written /* [out] non-NULL */
1151  )
1152 {
1153  char* src = (char*) src_buf;
1154  char* dst = (char*) dst_buf;
1155 
1156  *src_read = 0;
1157  *dst_written = 0;
1158  if (!src_size || !dst_size || !dst || !src)
1159  return;
1160 
1161  for ( ; *src_read != src_size && *dst_written != dst_size;
1162  src++, (*src_read)++,
1163  dst++, (*dst_written)++)
1164  {
1165  char c = *src;
1166  switch (c) {
1167  case '\377':
1168  case '\v':
1169  if (*dst_written + 2 > dst_size) {
1170  break;
1171  }
1172  *dst = '\377';
1173  dst++;
1174  (*dst_written)++;
1175  break;
1176  case '\n':
1177  *dst = '\v';
1178  continue;
1179  }
1180  *dst = c;
1181  }
1182 }
1183 
1184 
1185 
1186 /** Get base name of application.
1187  * Return a pointer to a newly allocated memory with zero-terminated string.
1188  */
1189 static char* s_GetAppBaseName(const char* path)
1190 {
1191  const char* p = path;
1192  const char* s;
1193  char* name;
1194 
1195  /* Find file name */
1196  for (s = p; *p; ++p ) {
1197  if ((*p == '/') || (*p == '\\') || (*p == ':')) {
1198  /* Found a separator, step over it and any others which immediately follow it */
1199  while ((*p == '/') || (*p == '\\') || (*p == ':')) {
1200  ++p;
1201  }
1202  /* If we didn't reach the end of the path string */
1203  if ( *p ) {
1204  /* We have a new candidate for the file name */
1205  s = p;
1206  } else {
1207  /* otherwise strip off any trailing dir separators */
1208  while ((p > s) && ((*--p == '/') || (*p == '\\')));
1209  /* Now, 's' points to the start of the file name, and 'p' to the end */
1210  break;
1211  }
1212  }
1213  }
1214  if (s == p) {
1215  return NULL;
1216  }
1217  name = s_StrDup(s);
1218  if (!name) {
1219  return NULL;
1220  }
1221 #if defined(NCBI_OS_MSWIN)
1222  /* Find and cut file extension, MS Windows only */
1223  while ((p > s) && (*--p != '.'));
1224  if (s != p) {
1225  name[p-s] = '\0';
1226  }
1227 #endif
1228  return name;
1229 }
1230 
1231 
1232 /** Create thread-specific context.
1233  */
1235 {
1236  /* Allocate memory for context structure */
1238  assert(ctx);
1239  memset((char*)ctx, 0, sizeof(TNcbiLog_Context_Data));
1240  /* Initialize context values, all other values = 0 */
1241  ctx->tid = s_GetTID();
1242  ctx->tsn = 1;
1243  return ctx;
1244 }
1245 
1246 
1247 /** Attach thread-specific context.
1248  */
1250 {
1252  if ( !ctx ) {
1253  return 0;
1254  }
1255  /* Get current context */
1256  if ( sx_TlsIsInit ) {
1257  prev = s_TlsGetValue();
1258  } else {
1259  prev = sx_ContextST;
1260  }
1261  /* Do not attach context if some different context is already attached */
1262  if (prev && prev!=ctx) {
1263  return 0;
1264  }
1265  /* Set new context */
1266  if ( sx_TlsIsInit ) {
1267  s_TlsSetValue((void*)ctx);
1268  } else {
1269  sx_ContextST = ctx;
1270  }
1271  return 1 /*true*/;
1272 }
1273 
1274 
1275 /** Get pointer to the thread-specific context.
1276  */
1278 {
1280  /* Get context for current thread, or use global value for ST mode */
1281  if ( sx_TlsIsInit ) {
1282  ctx = s_TlsGetValue();
1283  } else {
1284  ctx = sx_ContextST;
1285  }
1286  /* Create new context if not created/attached yet */
1287  if ( !ctx ) {
1288  /* Special case, context for current thread was already destroyed */
1289  assert(sx_IsInit != 2);
1290  /* Create context */
1291  ctx = s_CreateContext();
1293  }
1294  assert(ctx);
1295  return ctx;
1296 }
1297 
1298 
1299 /** Destroy thread-specific context.
1300  */
1301 static void s_DestroyContext(void)
1302 {
1304  if ( sx_TlsIsInit ) {
1305  ctx = s_TlsGetValue();
1306  free((void*)ctx);
1308  } else {
1309  free((void*)sx_ContextST);
1310  sx_ContextST = NULL;
1311  }
1312 }
1313 
1314 
1315 /** Determine logs location on the base of TOOLKITRC_FILE.
1316  */
1317 static const char* s_GetToolkitRCLogLocation()
1318 {
1319  static const char* log_path = NULL;
1320  static const char kSectionName[] = "[Web_dir_to_port]";
1321 
1322  FILE* fp;
1323  char buf[FILENAME_MAX];
1324  char *line, *token, *p;
1325  int inside_section = 0 /*false*/;
1326  size_t line_size;
1327 
1328  if (log_path) {
1329  return log_path;
1330  }
1331 
1332  /* Try to get more specific location from configuration file */
1333  fp = fopen("/etc/toolkitrc", "rt");
1334  if (!fp) {
1335  return log_path;
1336  }
1337  /* Reserve first byte in the buffer for the case of non-absolute path */
1338  buf[0] = '/';
1339  line = buf + 1;
1340  line_size = sizeof(buf) - 1;
1341 
1342  /* Read configuration file */
1343  while (fgets(line, (int)line_size, fp) != NULL)
1344  {
1345  if (inside_section) {
1346  if (line[0] == '#') {
1347  /* Comment - skip */
1348  continue;
1349  }
1350  if (line[0] == '[') {
1351  /* New section started - stop */
1352  break;
1353  }
1354  p = strchr(line, '=');
1355  if (!p) {
1356  /* Skip not matched lines*/
1357  continue;
1358  }
1359  token = p + 1;
1360 
1361  /* Remove all spaces */
1362  while ((p > line) && (*--p == ' '));
1363 
1364  /* Compare path with file name */
1365  if (line[0] == '/') {
1366  /* absolute path */
1367  *++p = '\0';
1368  if (strncmp(line, sx_Info->app_full_name, strlen(sx_Info->app_full_name)) != 0) {
1369  continue;
1370  }
1371  } else {
1372  char c;
1373  /* not an absolute path */
1374  if (*p != '/') {
1375  *++p ='/';
1376  }
1377  /* save and restore byte used for string termination */
1378  c = *++p;
1379  *p = '\0';
1380  if (!strstr(sx_Info->app_full_name, buf)) {
1381  continue;
1382  }
1383  *p = c;
1384  }
1385  /* Get token value, removing spaces and following EOL */
1386  while (*token == ' ') token++;
1387  p = token + 1;
1388  while (*p && !(*p == ' ' || *p == '\n')) p++;
1389  *p = '\0';
1390 
1391  /* Compose full directory name */
1392  {{
1393  char path[FILENAME_MAX + 1];
1394  s_ConcatPath(kBaseLogDir, token, path, FILENAME_MAX + 1);
1395  log_path = s_StrDup(path);
1396  break;
1397  }}
1398  /* continue to next line */
1399  }
1400  if (memcmp(line, kSectionName, sizeof(kSectionName)) >= 0) {
1401  inside_section = 1;
1402  }
1403  }
1404  fclose(fp);
1405 
1406  return log_path;
1407 }
1408 
1409 
1410 /** Close log files for a current destination.
1411  Files can be fully cleaned for setting a new destination or just
1412  closed to be reopened later with the same destination.
1413  */
1414 static void s_CloseLogFiles(int/*bool*/ cleanup /* CLOSE_CLEANUP / CLOSE_FOR_REOPEN */)
1415 {
1416  /* Current destination */
1417 
1418  switch (sx_Info->destination) {
1419  case eNcbiLog_Default:
1420  case eNcbiLog_Stdlog:
1421  case eNcbiLog_Cwd:
1422  case eNcbiLog_File:
1423  /* Close files, see below */
1424  break;
1425  case eNcbiLog_Stdout:
1426  case eNcbiLog_Stderr:
1427  case eNcbiLog_Disable:
1432  return;
1433  default:
1434  TROUBLE_MSG("unknown destination");
1435  }
1436 
1437  /* Close files, if any are open */
1438 
1440 #if NCBILOG_USE_FILE_DESCRIPTORS
1442 #else
1443  fclose(sx_Info->file_log);
1444 #endif
1446  }
1447 
1449 #if NCBILOG_USE_FILE_DESCRIPTORS
1451 #else
1452  fclose(sx_Info->file_trace);
1453 #endif
1455  }
1456 
1458 #if NCBILOG_USE_FILE_DESCRIPTORS
1460 #else
1461  fclose(sx_Info->file_err);
1462 #endif
1464  }
1465 
1467 #if NCBILOG_USE_FILE_DESCRIPTORS
1469 #else
1470  fclose(sx_Info->file_perf);
1471 #endif
1473  }
1474 
1475  if (cleanup && sx_Info->file_log_name) {
1478  }
1479  if (cleanup && sx_Info->file_trace_name) {
1482  }
1483  if (cleanup && sx_Info->file_err_name) {
1486  }
1487  if (cleanup && sx_Info->file_perf_name) {
1490  }
1491  if (cleanup) {
1492  sx_Info->reuse_file_names = 0 /*false*/;
1493  }
1494 }
1495 
1496 
1497 /** Open file streams.
1498  * All file names should be already defined.
1499  */
1500 static int /*bool*/ s_OpenLogFiles(void)
1501 {
1502 #if NCBILOG_USE_FILE_DESCRIPTORS
1503  int flags = O_CREAT | O_APPEND | O_WRONLY;
1504  mode_t mode = 0664;
1505 #endif
1510 
1515 
1516  /* Log */
1517 #if NCBILOG_USE_FILE_DESCRIPTORS
1519 #else
1520  sx_Info->file_log = fopen(sx_Info->file_log_name, "a");
1521 #endif
1523  return 0 /*false*/;
1524  }
1525 
1526  /* Trace */
1527  if (sx_Info->split_log_file) {
1528 #if NCBILOG_USE_FILE_DESCRIPTORS
1530 #else
1531  sx_Info->file_trace = fopen(sx_Info->file_trace_name, "a");
1532 #endif
1534  return 0 /*false*/;
1535  }
1536  } else {
1538  }
1539 
1540  /* Err */
1541  if (sx_Info->split_log_file) {
1542 #if NCBILOG_USE_FILE_DESCRIPTORS
1544 #else
1545  sx_Info->file_err = fopen(sx_Info->file_err_name, "a");
1546 #endif
1548  return 0 /*false*/;
1549  }
1550  } else {
1552  }
1553 
1554  /* Perf */
1556 #if NCBILOG_USE_FILE_DESCRIPTORS
1558 #else
1559  sx_Info->file_perf = fopen(sx_Info->file_perf_name, "a");
1560 #endif
1562  return 0 /*false*/;
1563  }
1564  } else {
1566  }
1567 
1568  return 1 /*true*/;
1569 }
1570 
1571 
1572 /** (Re)Initialize logging file streams.
1573  * The path passed in parameter should have directory and base name for logging files.
1574  */
1575 static int /*bool*/ s_SetLogFiles(const char* path_with_base_name, int/*bool*/ is_applog)
1576 {
1577  char path[FILENAME_MAX + 1];
1578  size_t n;
1579 
1580  assert(path_with_base_name);
1581  /* Check max possible file name (path.trace) */
1582  n = strlen(path_with_base_name);
1583  assert(n);
1584  assert((n + 5 /*.perf*/) <= sizeof(path));
1585  memcpy(path, path_with_base_name, n);
1586 
1587  strcpy(path + n, ".log");
1588  sx_Info->file_log_name = s_StrDup(path);
1589  strcpy(path + n, ".trace");
1590  sx_Info->file_trace_name = s_StrDup(path);
1591  strcpy(path + n, ".err");
1592  sx_Info->file_err_name = s_StrDup(path);
1593  strcpy(path + n, ".perf");
1594  sx_Info->file_perf_name = s_StrDup(path);
1595 
1596  /* Open files */
1597  sx_Info->is_applog = is_applog;
1598  if (!s_OpenLogFiles()) {
1600  return 0 /*false*/;
1601  }
1603  return 1 /*true*/;
1604 }
1605 
1606 
1607 /** (Re)Initialize logging file streams.
1608  * Use application base name and specified directory as path for logging files.
1609  */
1610 static int /*bool*/ s_SetLogFilesDir(const char* dir, int/*bool*/ is_applog)
1611 {
1612  char path[FILENAME_MAX + 1];
1613 #if defined(NCBI_OS_UNIX)
1614  char filename_buf[FILENAME_MAX + 1];
1615 #endif
1616  const char* filename = NULL;
1617  size_t n, filelen;
1618 
1619  assert(dir);
1620  n = strlen(dir);
1621  assert(n);
1622 
1623  /* When using applog, create separate log file for each user */
1624  /* to avoid permission problems */
1625 
1626 #if 0
1627  -- GUID approach for file names
1628  if (is_applog) {
1629  int nbuf;
1630  int x_guid_hi, x_guid_lo;
1631  /* sprintf() overflow guard */
1632  if (strlen(sx_Info->app_base_name)
1633  + 1 /* . */
1634  + 16 /* guid string */
1635  >= FILENAME_MAX) {
1636  return 0;
1637  }
1638  x_guid_hi = (int)((sx_Info->guid >> 32) & 0xFFFFFFFF);
1639  x_guid_lo = (int) (sx_Info->guid & 0xFFFFFFFF);
1640  nbuf = sprintf(filename_buf, "%s.%08X%08X", sx_Info->app_base_name, x_guid_hi, x_guid_lo);
1641  if (nbuf <= 0) {
1642  return 0;
1643  }
1644  filelen = (size_t)nbuf;
1645  filename = filename_buf;
1646  }
1647 #endif
1648 
1649 #if defined(NCBI_OS_UNIX)
1650  if (is_applog) {
1651  int nbuf;
1652  /* sprintf() overflow guard */
1653  if (strlen(sx_Info->app_base_name)
1654  + 1 /* . */
1655  + 10 /* max(uid_t) ~ MAX_UINT32 ~ 4,294,967,295 */
1656  >= FILENAME_MAX) {
1657  return 0;
1658  }
1659  nbuf = sprintf(filename_buf, "%s.%d", sx_Info->app_base_name, geteuid());
1660  if (nbuf <= 0) {
1661  return 0;
1662  }
1663  filelen = (size_t)nbuf;
1664  filename = filename_buf;
1665  }
1666 #endif
1667  if (!filename) {
1668  filename = sx_Info->app_base_name;
1669  filelen = strlen(filename);
1670  assert(filelen);
1671  }
1672 
1673  /* Check max possible file name (dir/basename.trace) */
1674  assert((n + 1 + filelen + 5) <= sizeof(path));
1675  s_ConcatPathEx(dir, n, filename, filelen, path, FILENAME_MAX + 1);
1676 
1677  /* Set logging files */
1678  return s_SetLogFiles(path, is_applog);
1679 }
1680 
1681 
1682 /** (Re)Initialize destination.
1683  */
1684 static void s_InitDestination(const char* logfile_path)
1685 {
1686  time_t now;
1688 
1689 #if NCBILOG_USE_FILE_DESCRIPTORS
1690  if (sx_Info->file_log == STDOUT_FILENO || sx_Info->file_log == STDERR_FILENO) {
1691  /* We already have destination set to stdout/stderr -- don't need to reopen it */
1692  return;
1693  }
1694 #else
1695  if (sx_Info->file_log == stdout || sx_Info->file_log == stderr) {
1696  /* We already have destination set to stdout/stderr -- don't need to reopen it */
1697  return;
1698  }
1699 #endif
1700 
1701 #if 0
1702  -- use regular behavior with reopening user files as well
1703 
1704  /* We already have logging set to user defined file(s) -- don't need to reopen it */
1705  if (sx_Info->destination == eNcbiLog_File &&
1707  return;
1708  }
1709 #endif
1710 
1711  /* Reopen all files every 1 minute */
1712 
1713  time(&now);
1714  if (now - sx_Info->last_reopen_time < 60) {
1715  return;
1716  }
1717  sx_Info->last_reopen_time = now;
1718 
1719  /* Try to open files */
1720 
1722  sx_Info->destination == eNcbiLog_File) && logfile_path) {
1723  /* special case to redirect all logging to specified files */
1725  if (s_SetLogFiles(logfile_path, NO_LOG)) {
1726  return;
1727  }
1728  /* Error: disable logging.
1729  The error reporting should be done on an upper level(s) outside of the CLog.
1730  */
1732  return;
1733  }
1734 
1735  /* Close */
1737 
1742 
1743  /* Destination and file names didn't changed, just reopen files */
1744  if (sx_Info->reuse_file_names) {
1745  if (s_OpenLogFiles()) {
1746  return;
1747  }
1748  /* Error: failed to reopen */
1750  /* Will try again from scratch (below), can lead to change the logging location */
1751  }
1752  /* Reopening failed. For a local "file" logging this is an error -- disable logging */
1753  if (sx_Info->destination == eNcbiLog_File) {
1755  return;
1756  }
1757 
1758  /* Try default log location */
1759  {{
1760  char xdir[FILENAME_MAX + 1];
1761  const char* dir;
1762 
1763  /* /log */
1764  if (sx_Info->destination != eNcbiLog_Cwd) {
1765  /* toolkitrc file */
1766  dir = s_GetToolkitRCLogLocation();
1767  if (dir) {
1768  if (s_SetLogFilesDir(dir, TO_LOG)) {
1769  return;
1770  }
1771  }
1772  /* server port */
1773  if (sx_Info->server_port) {
1774  sprintf(xdir, "%s%d", kBaseLogDir, sx_Info->server_port);
1775  if (s_SetLogFilesDir(xdir, TO_LOG)) {
1776  return;
1777  }
1778  }
1779 
1780  /* /log/srv */
1781  dir = s_ConcatPath(kBaseLogDir, "srv", xdir, FILENAME_MAX + 1);
1782  if (dir) {
1783  if (s_SetLogFilesDir(dir, TO_LOG)) {
1784  return;
1785  }
1786  }
1787  /* /log/fallback */
1788  dir = s_ConcatPath(kBaseLogDir, "fallback", xdir, FILENAME_MAX + 1);
1789  if (dir) {
1790  if (s_SetLogFilesDir(dir, TO_LOG)) {
1791  return;
1792  }
1793  }
1794  /* /log/{{logsite}} */
1795  if (sx_Info->logsite && sx_Info->logsite[0] != '\0') {
1796  dir = s_ConcatPath(kBaseLogDir, sx_Info->logsite, xdir, FILENAME_MAX + 1);
1797  if (dir) {
1798  if (s_SetLogFilesDir(dir, TO_LOG)) {
1799  return;
1800  }
1801  }
1802  }
1803  }
1804  /* Try current directory -- eNcbiLog_Stdlog, eNcbiLog_Cwd */
1806  char* cwd;
1807  #if defined(NCBI_OS_UNIX)
1808  cwd = getcwd(NULL, 0);
1809  #elif defined(NCBI_OS_MSWIN)
1810  cwd = _getcwd(NULL, 0);
1811  #endif
1812  if (cwd && s_SetLogFilesDir(cwd, NO_LOG)) {
1814  free(cwd);
1815  return;
1816  }
1817  free(cwd);
1818  }
1819  /* Fallback - use stderr */
1821  }}
1822  }
1823 
1824  /* Use stdout/stderr */
1825  switch (sx_Info->destination) {
1826  case eNcbiLog_Stdout:
1827 #if NCBILOG_USE_FILE_DESCRIPTORS
1832 #else
1833  sx_Info->file_trace = stdout;
1834  sx_Info->file_log = stdout;
1835  sx_Info->file_err = stdout;
1836  sx_Info->file_perf = stdout;
1837 #endif
1838  break;
1839  case eNcbiLog_Stderr:
1840 #if NCBILOG_USE_FILE_DESCRIPTORS
1841  sx_Info->file_trace = STDERR_FILENO;
1842  sx_Info->file_log = STDERR_FILENO;
1843  sx_Info->file_err = STDERR_FILENO;
1844  sx_Info->file_perf = STDERR_FILENO;
1845 #else
1846  sx_Info->file_trace = stderr;
1847  sx_Info->file_log = stderr;
1848  sx_Info->file_err = stderr;
1849  sx_Info->file_perf = stderr;
1850 #endif
1851  break;
1852  default:
1853  TROUBLE;
1854  }
1855 }
1856 
1857 
1858 static void s_SetHost(const char* host)
1859 {
1860  if (host && *host) {
1861  size_t len;
1862  len = strlen(host);
1863  if (len> NCBILOG_HOST_MAX) {
1865  }
1866  memcpy((char*)sx_Info->host, host, len);
1867  sx_Info->host[len] = '\0';
1868  } else {
1869  sx_Info->host[0] = '\0';
1870  }
1871 }
1872 
1873 
1874 static void s_SetClient(char* dst, const char* client)
1875 {
1876  if (client && *client) {
1877  size_t len;
1878  len = strlen(client);
1879  if (len > NCBILOG_CLIENT_MAX) {
1881  }
1882  memcpy(dst, client, len);
1883  dst[len] = '\0';
1884  } else {
1885  dst[0] = '\0';
1886  }
1887 }
1888 
1889 
1890 static void s_SetSession(char* dst, const char* session)
1891 {
1892  if (session && *session) {
1893  /* URL-encode */
1894  size_t len, r_len, w_len;
1895  len = strlen(session);
1896  s_URL_Encode(session, len, &r_len, dst, 3*NCBILOG_SESSION_MAX, &w_len);
1897  verify(len == r_len);
1898  dst[w_len] = '\0';
1899  } else {
1900  dst[0] = '\0';
1901  }
1902 }
1903 
1904 
1905 static void s_SetHitID(char* dst, const char* hit_id)
1906 {
1907  if (hit_id && *hit_id) {
1908  /*TODO: Validate hit ID ?? */
1909  /* URL-encode */
1910  size_t len, r_len, w_len;
1911  len = strlen(hit_id);
1912  s_URL_Encode(hit_id, len, &r_len, dst, 3*NCBILOG_HITID_MAX, &w_len);
1913  verify(len == r_len);
1914  dst[w_len] = '\0';
1915  } else {
1916  dst[0] = '\0';
1917  }
1918 }
1919 
1920 
1922 {
1924 
1925  /* Get application state (context-specific) */
1926  state = (ctx->state == eNcbiLog_NotSet) ? sx_Info->state : ctx->state;
1927  switch (state) {
1928  case eNcbiLog_RequestBegin:
1929  case eNcbiLog_Request:
1930  return 1;
1931  default:
1932  break;
1933  }
1934  return 0;
1935 }
1936 
1937 
1938 static char* s_GenerateSID_Str_Ex(char* dst, int /*bool*/ use_logging_api, TNcbiLog_UInt8 uid)
1939 {
1940  TNcbiLog_UInt8 rid;
1941  int hi, lo, n;
1942 
1943  if (use_logging_api) {
1944  if (!sx_Info->guid) {
1945  sx_Info->guid = uid ? uid : s_CreateUID();
1946  }
1947  uid = sx_Info->guid;
1948  rid = sx_Info->rid;
1949  } else {
1950  uid = uid ? uid : s_CreateUID();
1951  rid = 0;
1952  }
1953  hi = (int)((uid >> 32) & 0xFFFFFFFF);
1954  lo = (int) (uid & 0xFFFFFFFF);
1955  n = sprintf(dst, "%08X%08X_%04" NCBILOG_UINT8_FORMAT_SPEC "SID", hi, lo, rid);
1956  if (n <= 0) {
1957  return NULL;
1958  }
1959  return dst;
1960 }
1961 
1962 
1963 static char* s_GenerateSID_Str(char* dst)
1964 {
1965  return s_GenerateSID_Str_Ex(dst, 1 /*api call*/, 0 /*autogenerated UID*/);
1966 }
1967 
1968 
1969 static char* s_GenerateHitID_Str_Ex(char* dst, int /*bool*/ is_api_call, TNcbiLog_UInt8 uid)
1970 {
1971  TNcbiLog_UInt8 tid, rid, us, hi, lo;
1972  unsigned int b0, b1, b2, b3;
1973  time_t time_sec;
1974  unsigned long time_ns;
1975  int n;
1976 
1977  if (is_api_call) {
1978  if (!sx_Info->guid) {
1979  sx_Info->guid = uid ? uid : s_CreateUID();
1980  }
1981  hi = sx_Info->guid;
1982  rid = (TNcbiLog_UInt8)(sx_Info->rid & 0xFFFFFF) << 16;
1983  } else {
1984  // some external call, create a new UID especially for caller
1985  hi = uid ? uid : s_CreateUID();
1986  rid = 0;
1987  }
1988  b3 = (unsigned int)((hi >> 32) & 0xFFFFFFFF);
1989  b2 = (unsigned int)(hi & 0xFFFFFFFF);
1990  tid = (s_GetTID() & 0xFFFFFF) << 40;
1991  if (!s_GetTimeT(&time_sec, &time_ns)) {
1992  us = 0;
1993  } else {
1994  us = (time_ns/1000/16) & 0xFFFF;
1995  }
1996  lo = tid | rid | us;
1997  b1 = (unsigned int)((lo >> 32) & 0xFFFFFFFF);
1998  b0 = (unsigned int)(lo & 0xFFFFFFFF);
1999  n = sprintf(dst, "%08X%08X%08X%08X", b3, b2, b1, b0);
2000  if (n <= 0) {
2001  return NULL;
2002  }
2003  return dst;
2004 }
2005 
2006 
2007 static char* s_GenerateHitID_Str(char* dst)
2008 {
2009  return s_GenerateHitID_Str_Ex(dst, 1 /*api call*/, 0 /*autogenerated UID*/);
2010 }
2011 
2012 
2013 /** Generate new unique process ID.
2014  */
2016 {
2017  return s_CreateUID();
2018 }
2019 
2020 
2021 /** Generate new Hit ID string.
2022  */
2023 extern const char* NcbiLogP_GenerateHitID(char* buf, size_t n, TNcbiLog_UInt8 uid)
2024 {
2025  if (n <= NCBILOG_HITID_MAX) {
2026  return NULL;
2027  }
2028  if (!s_GenerateHitID_Str_Ex(buf, 0 /*external call*/, uid)) {
2029  return NULL;
2030  }
2031  return buf;
2032 }
2033 
2034 
2035 /** Generate new SID string.
2036  */
2037 extern const char* NcbiLogP_GenerateSID(char* buf, size_t n, TNcbiLog_UInt8 uid)
2038 {
2039  if (n <= NCBILOG_SESSION_MAX) {
2040  return NULL;
2041  }
2042  if (!s_GenerateSID_Str_Ex(buf, 0 /*ext api call*/, uid)) {
2043  return NULL;
2044  }
2045  return buf;
2046 }
2047 
2048 
2049 
2050 
2051 /******************************************************************************
2052  * Print
2053  */
2054 
2055 #if NCBILOG_USE_FILE_DESCRIPTORS
2056 
2057 static size_t s_Write(int fd, const void *buf, size_t count)
2058 {
2059  const char* ptr = (const char*) buf;
2060  size_t n = count;
2061  ssize_t n_written;
2062 
2063  if (count == 0) {
2064  return 0;
2065  }
2066  do {
2067  n_written = write(fd, ptr, n);
2068  if (n_written == 0) {
2069  return count - n;
2070  }
2071  if ( n_written < 0 ) {
2072  if (errno == EINTR) {
2073  continue;
2074  }
2075  return count - n;
2076  }
2077  n -= (size_t)n_written;
2078  ptr += n_written;
2079  }
2080  while (n > 0);
2081  return count;
2082 }
2083 
2084 #endif
2085 
2086 
2087 /** Post prepared message into the log.
2088  * The severity parameter is necessary to choose correct logging file.
2089  */
2091 {
2093  size_t n_write;
2094 #if NCBILOG_USE_FILE_DESCRIPTORS
2095  size_t n;
2096 #else
2097  int n;
2098 #endif
2099 
2101  return;
2102  }
2103  /* Reopen logging files, if necessary */
2105  /* Destination can be disabled on reopening, so check again */
2107  return;
2108  }
2109 
2110  switch (diag) {
2111  case eDiag_Trace:
2112  f = sx_Info->file_trace;
2113  break;
2114  case eDiag_Err:
2115  f = sx_Info->file_err;
2116  break;
2117  case eDiag_Log:
2118  f = sx_Info->file_log;
2119  break;
2120  case eDiag_Perf:
2121  f = sx_Info->file_perf;
2122  break;
2123  default:
2124  TROUBLE;
2125  }
2126 
2127  /* Write */
2129 
2130  n_write = strlen(sx_Info->message);
2131  VERIFY_CATCH(n_write <= NCBILOG_ENTRY_MAX);
2132 
2133 #if NCBILOG_USE_FILE_DESCRIPTORS
2134  sx_Info->message[n_write] = '\n';
2135  n_write++;
2136  sx_Info->message[n_write] = '\0';
2137  n = s_Write(f, sx_Info->message, n_write);
2138  VERIFY(n == n_write);
2139  /* fdatasync(f); */
2140 #else
2141  n = fprintf(f, "%s\n", sx_Info->message);
2142  VERIFY(n == n_write + 1);
2143  fflush(f);
2144 #endif
2145 
2146  /* Increase posting serial numbers */
2147  sx_Info->psn++;
2148  ctx->tsn++;
2149 
2150  /* Reset posting time if no user time defined */
2151  if (sx_Info->user_posting_time == 0) {
2152  sx_Info->post_time.sec = 0;
2153  sx_Info->post_time.ns = 0;
2154  }
2155 
2156 CATCH:
2157  return;
2158 }
2159 
2160 
2161 /* Symbols abbreviation for application state, see ENcbiLog_AppState */
2162 static const char* sx_AppStateStr[] = {
2163  "NS", "PB", "P", "PE", "RB", "R", "RE"
2164 };
2165 
2166 /** Print common prefix to message buffer.
2167  * Return number of written bytes (current position in message buffer), or zero on error.
2168  * See documentation about log format:
2169  * https://ncbi.github.io/cxx-toolkit/pages/ch_log#ch_core.The_New_Post_Format
2170  * C++ implementation: CDiagContext::WriteStdPrefix() (src/corelib/ncbidiag.cpp)
2171  */
2173 {
2174  TNcbiLog_PID x_pid;
2175  TNcbiLog_Counter x_rid;
2176  ENcbiLog_AppState x_st;
2177  const char *x_state, *x_host, *x_client, *x_session, *x_appname;
2178  char x_time[24];
2179  int x_guid_hi, x_guid_lo;
2180  int n;
2181  int inside_request;
2182 
2183  /* Calculate GUID */
2184  if ( !sx_Info->guid ) {
2185  sx_Info->guid = s_CreateUID();
2186  }
2187  x_guid_hi = (int)((sx_Info->guid >> 32) & 0xFFFFFFFF);
2188  x_guid_lo = (int) (sx_Info->guid & 0xFFFFFFFF);
2189 
2190  /* Get application state (context-specific) */
2191  x_st = (ctx->state == eNcbiLog_NotSet) ? sx_Info->state : ctx->state;
2192  x_state = sx_AppStateStr[x_st];
2193  switch (x_st) {
2194  case eNcbiLog_RequestBegin:
2195  case eNcbiLog_Request:
2196  case eNcbiLog_RequestEnd:
2197  inside_request = 1;
2198  break;
2199  default:
2200  inside_request = 0;
2201  }
2202 
2203  /* Get posting time string (current or specified by user) */
2204  if (!sx_Info->post_time.sec) {
2205  if (!s_GetTime((STime*)&sx_Info->post_time)) {
2206  /* error */
2207  return 0;
2208  }
2209  }
2210  if (!s_GetTimeStr(x_time, sx_Info->post_time.sec, sx_Info->post_time.ns)) {
2211  return 0; /* error */
2212  }
2213 
2214  /* Define properties */
2215 
2216  if (!sx_Info->host[0]) {
2218  }
2219  x_pid = sx_Info->pid ? sx_Info->pid : s_GetPID();
2220  x_rid = ctx->rid ? ctx->rid : 0;
2221  x_host = sx_Info->host[0] ? (char*)sx_Info->host : UNKNOWN_HOST;
2222  x_appname = sx_Info->appname[0] ? (char*)sx_Info->appname : UNKNOWN_APPNAME;
2223 
2224  /* client */
2225  if (inside_request && ctx->is_client_set) {
2226  x_client = ctx->client[0] ? (char*)ctx->client : UNKNOWN_CLIENT;
2227  } else {
2228  x_client = sx_Info->client[0] ? (char*)sx_Info->client : UNKNOWN_CLIENT;
2229  }
2230  /* session */
2231  if (inside_request && ctx->is_session_set) {
2232  x_session = ctx->session[0] ? (char*)ctx->session : UNKNOWN_SESSION;
2233  } else {
2234  x_session = sx_Info->session[0] ? (char*)sx_Info->session : UNKNOWN_SESSION;
2235  }
2236 
2237  n = sprintf(sx_Info->message,
2239  "/%04" NCBILOG_UINT8_FORMAT_SPEC "/%-2s %08X%08X %04" NCBILOG_UINT8_FORMAT_SPEC \
2240  "/%04" NCBILOG_UINT8_FORMAT_SPEC " %s %-15s %-15s %-24s %s ",
2241  x_pid,
2242  ctx->tid,
2243  x_rid,
2244  x_state,
2245  x_guid_hi, x_guid_lo,
2246  sx_Info->psn,
2247  ctx->tsn,
2248  x_time,
2249  x_host,
2250  x_client,
2251  x_session,
2252  x_appname
2253  );
2254  if (n <= 0) {
2255  return 0; /* error */
2256  }
2257  return (size_t)n;
2258 }
2259 
2260 
2261 /** Add parameters pair to the list if not empty. Update and return index.
2262  * Because this method is for internal usage only, to print automatically
2263  * logged extra parameters, neither key or value can be empty here.
2264  */
2265 static int s_AddParamsPair(SNcbiLog_Param params[], int index, const char* key, const char* value)
2266 {
2267  assert(key || key[0]);
2268  if (!value || !value[0]) {
2269  return index;
2270  }
2271  params[index].key = key;
2272  params[index].value = value;
2273  return ++index;
2274 }
2275 
2276 
2277 /** Print one parameter's pair (key, value) to message buffer.
2278  * Automatically URL encode each key and value.
2279  * Return new position in the buffer.
2280  */
2281 static size_t s_PrintParamsPair(char* dst, size_t pos, const char* key, const char* value)
2282 {
2283  size_t len, r_len, w_len;
2284 
2285  if (pos >= NCBILOG_ENTRY_MAX) {
2286  return pos; /* error, pre-check on overflow */
2287  }
2288 
2289  /* Key */
2290  if (!key || key[0] == '\0') {
2291  return pos; /* error */
2292  }
2293  len = strlen(key);
2294  s_URL_Encode(key, len, &r_len, dst + pos, NCBILOG_ENTRY_MAX - pos, &w_len);
2295  pos += w_len;
2296  if (pos > NCBILOG_ENTRY_MAX-2) {
2297  /* we should have space at least for 2 chars '=<value>' */
2298  return pos; /* error, overflow */
2299  }
2300 
2301  /* Value */
2302  dst[pos++] = '=';
2303  if (!value || value[0] == '\0') {
2304  return pos;
2305  }
2306  len = strlen(value);
2307  s_URL_Encode(value, len, &r_len, dst + pos, NCBILOG_ENTRY_MAX - pos, &w_len);
2308  pos += w_len;
2309  if (pos > NCBILOG_ENTRY_MAX) {
2310  return pos; /* error, overflow */
2311  }
2312  dst[pos] = '\0';
2313 
2314  return pos;
2315 }
2316 
2317 
2318 /** Print parameters to message buffer.
2319  * Return new position in the buffer.
2320  */
2321 static size_t s_PrintParams(char* dst, size_t pos, const SNcbiLog_Param* params)
2322 {
2323  int/*bool*/ amp = 0;
2324  size_t new_pos = 0;
2325 
2326  /* Walk through the list of arguments */
2327  if (params) {
2328  while (params && params->key && pos < NCBILOG_ENTRY_MAX) {
2329  if (params->key[0] != '\0') {
2330  if (amp) {
2331  dst[pos++] = '&';
2332  } else {
2333  amp = 1;
2334  }
2335  /* Write 'whole' pair or ignore */
2336  new_pos = s_PrintParamsPair(dst, pos, params->key, params->value);
2337  /* Check on overflow */
2338  VERIFY_CATCH(new_pos <= NCBILOG_ENTRY_MAX);
2339  pos = new_pos;
2340  }
2341  params++;
2342  }
2343  }
2344 
2345 CATCH:
2346  dst[pos] = '\0';
2347  return pos;
2348 }
2349 
2350 
2351 /** Print parameters to message buffer (string version).
2352  * The 'params' must be already prepared pairs with URL-encoded key and value.
2353  * Return new position in the buffer.
2354  */
2355 static size_t s_PrintParamsStr(char* dst, size_t pos, const char* params)
2356 {
2357  size_t len;
2358 
2359  if (!params) {
2360  return pos;
2361  }
2362  /* Check on overflow */
2364  len = min_value(strlen(params), NCBILOG_ENTRY_MAX-pos);
2365  memcpy(dst + pos, params, len);
2366  pos += len;
2367  dst[pos] = '\0';
2368 
2369 CATCH:
2370  return pos;
2371 }
2372 
2373 
2374 /* Severity string representation */
2375 static const char* sx_SeverityStr[] = {
2376  "Trace", "Info", "Warning", "Error", "Critical", "Fatal"
2377 };
2378 
2379 /** Print a message with severity to message buffer.
2380  */
2381 static void s_PrintMessage(ENcbiLog_Severity severity, const char* msg, int/*bool*/ print_as_note)
2382 {
2384  size_t pos, r_len, w_len;
2385  char* buf;
2387 
2388  switch (severity) {
2389  case eNcbiLog_Trace:
2390  case eNcbiLog_Info:
2391  diag = eDiag_Trace;
2392  break;
2393  case eNcbiLog_Warning:
2394  case eNcbiLog_Error:
2395  case eNcbiLog_Critical:
2396  case eNcbiLog_Fatal:
2397  diag = eDiag_Err;
2398  break;
2399  default:
2400  TROUBLE;
2401  }
2402  /* Check minimum allowed posting level */
2403  if (severity < sx_Info->post_level) {
2404  return;
2405  }
2406 
2407  MT_LOCK_API;
2408  ctx = s_GetContext();
2410 
2411  /* Prefix */
2412  buf = sx_Info->message;
2413  pos = s_PrintCommonPrefix(ctx);
2414  VERIFY_CATCH(pos);
2415 
2416  /* Severity */
2417  if (print_as_note) {
2418  pos += (size_t) sprintf(buf + pos, "Note[%c]: ", sx_SeverityStr[severity][0]);
2419  } else {
2420  pos += (size_t) sprintf(buf + pos, "%s: ", sx_SeverityStr[severity]);
2421  }
2422 
2423  /* Message */
2424  s_EscapeNewlines(msg, strlen(msg), &r_len, buf + pos, NCBILOG_ENTRY_MAX - pos, &w_len);
2425  pos += w_len;
2426  buf[pos] = '\0';
2427 
2428  /* Post a message */
2429  s_Post(ctx, diag);
2430 
2431 CATCH:
2432  MT_UNLOCK;
2433  if (severity == eNcbiLog_Fatal) {
2434  s_Abort(0,0); /* no additional error reporting */
2435  }
2436  return;
2437  }
2438 
2439 
2440 
2441 /******************************************************************************
2442  * NcbiLog
2443  */
2444 
2445 static void s_Init(const char* appname)
2446 {
2447  size_t len, r_len, w_len;
2448  char* app = NULL;
2449 
2450  /* Initialize TLS; disable using TLS for ST applications */
2451  if (sx_MTLock) {
2452  s_TlsInit();
2453  } else {
2454  sx_TlsIsInit = 0;
2455  }
2456 
2457  /* Create info structure */
2458  assert(!sx_Info);
2459  sx_Info = (TNcbiLog_Info*) malloc(sizeof(TNcbiLog_Info));
2460  assert(sx_Info);
2461  memset((char*)sx_Info, 0, sizeof(TNcbiLog_Info));
2462 
2463  /* Set defaults */
2464  sx_Info->psn = 1;
2466 #if defined(NDEBUG)
2468 #else
2470 #endif
2475 
2476  /* If defined, use hard-coded application name from
2477  "-D NCBI_C_LOG_APPNAME=appname" on a compilation step */
2478 #if defined(NCBI_C_LOG_APPNAME)
2479  #define MACRO2STR_(x) #x
2480  #define MACRO2STR(x) MACRO2STR_(x)
2481  app = MACRO2STR(NCBI_C_LOG_APPNAME);
2482 #else
2483  app = (char*)appname;
2484 #endif
2485  /* Set application name */
2486  if (!(app && *app)) {
2487  app = "UNKNOWN";
2488  }
2489  sx_Info->app_full_name = s_StrDup(app);
2493  /* URL-encode base name and use it as display name */
2494  len = strlen(sx_Info->app_base_name);
2496  (char*)sx_Info->appname, 3*NCBILOG_APPNAME_MAX, &w_len);
2497  verify(len == r_len);
2498  sx_Info->appname[w_len] = '\0';
2499 
2500  /* Allocate memory for message buffer */
2503 
2504  /* Try to get LOG_ISSUED_SUBHIT_LIMIT value, see docs for it */
2505  {{
2506  unsigned int v; /* necessary to avoid compilation warnings */
2507  if (NcbiLogP_GetEnv_UInt("LOG_ISSUED_SUBHIT_LIMIT", &v) == 0) {
2509  } else {
2510  /* Not defined, use default, same as for C++ toolkit */
2511  sx_Info->phid_sub_id_limit = 200;
2512  }
2513  }}
2514 
2515  /* Logging is initialized now and can be used */
2516  sx_IsEnabled = 1 /*true*/;
2517 }
2518 
2519 
2520 extern void NcbiLog_Init(const char* appname,
2521  TNcbiLog_MTLock mt_lock,
2522  ENcbiLog_MTLock_Ownership mt_lock_ownership)
2523 {
2524  if (sx_IsInit) {
2525  /* NcbiLog_Init() is already in progress or done */
2526  /* This function can be called only once */
2527  VERIFY(!sx_IsInit);
2528  /* error */
2529  return;
2530  }
2531  /* Start initialization */
2532  /* The race condition is possible here if NcbiLog_Init() is simultaneously
2533  called from several threads. But NcbiLog_Init() should be called
2534  only once, so we can leave this to user's discretion.
2535  */
2536  sx_IsInit = 1;
2537  sx_MTLock = mt_lock;
2538  sx_MTLock_Own = (mt_lock_ownership == eNcbiLog_MT_TakeOwnership);
2539 
2540  MT_INIT;
2541  MT_LOCK;
2542  s_Init(appname);
2543  MT_UNLOCK;
2544 }
2545 
2546 
2547 extern void NcbiLog_InitMT(const char* appname)
2548 {
2550  NcbiLog_Init(appname, mt_lock, eNcbiLog_MT_TakeOwnership);
2551 }
2552 
2553 
2554 extern void NcbiLog_InitST(const char* appname)
2555 {
2557 }
2558 
2559 
2560 extern void NcbiLog_InitForAttachedContext(const char* appname)
2561 {
2562  /* For POSIX we have static initialization for default MT lock,
2563  and we can start using locks right now. But on Windows this
2564  is not possible. So, will do initialization first.
2565  */
2566 #if defined(NCBI_OS_MSWIN)
2567  int is_init = InterlockedCompareExchange(&sx_IsInit, 1, 0);
2568  if (is_init) {
2569  /* Initialization is already in progress or done */
2570  return;
2571  }
2572  MT_INIT;
2573  MT_LOCK;
2574 #elif defined(NCBI_OS_UNIX)
2575  MT_LOCK;
2576  if (sx_IsInit) {
2577  /* Initialization is already in progress or done */
2578  MT_UNLOCK;
2579  return;
2580  }
2581  sx_IsInit = 1;
2582 #endif
2583  s_Init(appname);
2584  MT_UNLOCK;
2585 }
2586 
2587 
2588 extern void NcbiLog_InitForAttachedContextST(const char* appname)
2589 {
2590  NcbiLog_InitST(appname);
2591 }
2592 
2593 
2594 extern void NcbiLog_Destroy_Thread(void)
2595 {
2596  MT_LOCK;
2597  s_DestroyContext();
2598  MT_UNLOCK;
2599 }
2600 
2601 
2602 extern void NcbiLog_Destroy(void)
2603 {
2604  MT_LOCK;
2605  sx_IsEnabled = 0;
2606  sx_IsInit = 2; /* still TRUE to prevent recurring initialization, but not default 1 */
2607 
2608  /* Close files */
2610 
2611  /* Free memory */
2612  if (sx_Info->message) {
2613  free(sx_Info->message);
2614  }
2615  if (sx_Info->app_full_name) {
2617  }
2618  if (sx_Info->app_base_name) {
2620  }
2621  if (sx_Info) {
2622  free((void*)sx_Info);
2623  sx_Info = NULL;
2624  }
2625  /* Destroy thread-specific context and TLS */
2626  s_DestroyContext();
2627  if (sx_TlsIsInit) {
2628  s_TlsDestroy();
2629  }
2630  /* Destroy MT support */
2631  if (sx_MTLock_Own) {
2633  }
2634  sx_MTLock = NULL;
2635 }
2636 
2637 
2638 extern void NcbiLogP_ReInit(void)
2639 {
2640  sx_IsInit = 0;
2641 }
2642 
2643 
2645 {
2647  /* Make initialization if not done yet */
2649  /* Create context */
2650  ctx = s_CreateContext();
2651  return ctx;
2652 }
2653 
2654 
2656 {
2657  int is_attached;
2658  if ( !ctx ) {
2659  return 0 /*false*/;
2660  }
2661  MT_LOCK_API;
2662  is_attached = s_AttachContext(ctx);
2663  MT_UNLOCK;
2664  return is_attached;
2665 }
2666 
2667 
2668 extern void NcbiLog_Context_Detach(void)
2669 {
2670  MT_LOCK_API;
2671  /* Reset context */
2672  if ( sx_TlsIsInit ) {
2674  } else {
2675  sx_ContextST = NULL;
2676  }
2677  MT_UNLOCK;
2678 }
2679 
2680 
2682 {
2683  assert(ctx);
2684  free(ctx);
2685 }
2686 
2687 
2688 /** Set application state -- internal version without MT locking.
2689  *
2690  * We have two states: global and context-specific.
2691  * We use global state if context-specific state is not specified.
2692  * Setting state to eNcbiLog_App* always overwrite context-specific
2693  * state. The eNcbiLog_Request* affect only context-specific state.
2694  */
2696 {
2697 #if !defined(NDEBUG)
2698  ENcbiLog_AppState s = (ctx->state == eNcbiLog_NotSet)
2699  ? sx_Info->state
2700  : ctx->state;
2701 #endif
2702  switch ( state ) {
2703  case eNcbiLog_AppBegin:
2704  if (!sx_DisableChecks) {
2706  }
2707  sx_Info->state = state;
2708  ctx->state = state;
2709  break;
2710  case eNcbiLog_AppRun:
2711  if (!sx_DisableChecks) {
2713  s == eNcbiLog_RequestEnd);
2714  }
2715  sx_Info->state = state;
2716  ctx->state = state;
2717  break;
2718  case eNcbiLog_AppEnd:
2719  if (!sx_DisableChecks) {
2721  }
2722  sx_Info->state = state;
2723  ctx->state = state;
2724  break;
2725  case eNcbiLog_RequestBegin:
2726  if (!sx_DisableChecks) {
2727  assert(s == eNcbiLog_AppBegin ||
2728  s == eNcbiLog_AppRun ||
2729  s == eNcbiLog_RequestEnd);
2730  }
2731  ctx->state = state;
2732  break;
2733  case eNcbiLog_Request:
2734  if (!sx_DisableChecks) {
2736  }
2737  ctx->state = state;
2738  break;
2739  case eNcbiLog_RequestEnd:
2740  if (!sx_DisableChecks) {
2741  assert(s == eNcbiLog_Request ||
2742  s == eNcbiLog_RequestBegin);
2743  }
2744  ctx->state = state;
2745  break;
2746  default:
2747  TROUBLE;
2748  }
2749 }
2750 
2751 
2752 extern ENcbiLog_Destination
2754 {
2755  char* logfile = NULL;
2756 
2757  MT_LOCK_API;
2758  /* Close current destination files, if any */
2760 
2761  /* Server port */
2762  if (!sx_Info->server_port) {
2763  const char* port_str = getenv("SERVER_PORT");
2764  if (port_str && *port_str) {
2765  char* e;
2766  unsigned long port = strtoul(port_str, &e, 10);
2767  if (port > 0 && port <= NCBILOG_PORT_MAX && !*e) {
2768  sx_Info->server_port = (unsigned int)port;
2769  }
2770  }
2771  }
2772  /* Set new destination */
2773  sx_Info->destination = ds;
2775  /* and force to initialize it */
2778  /* Special case to redirect default logging output */
2779  logfile = getenv("NCBI_CONFIG__LOG__FILE");
2780  if (logfile) {
2781  if (!*logfile) {
2782  logfile = NULL;
2783  } else {
2784  if (strcmp(logfile, "-") == 0) {
2786  logfile = NULL;
2787  }
2788  }
2789  }
2790  }
2791  s_InitDestination(logfile);
2792  /* Read destination back, it can change */
2793  ds = sx_Info->destination;
2794  }
2795  MT_UNLOCK;
2796  return ds;
2797 }
2798 
2799 
2800 extern ENcbiLog_Destination
2801 NcbiLog_SetDestinationFile(const char* logfile_base)
2802 {
2803  const char* logfile = logfile_base;
2805 
2806  MT_LOCK_API;
2807  /* Close current destination */
2809 
2810  if (!logfile && !*logfile ) {
2811  sx_Info->destination = eNcbiLog_Disable; /* error */
2812  MT_UNLOCK;
2813  return sx_Info->destination;
2814  }
2815  /* Special case to redirect file logging output to stderr */
2816  if (strcmp(logfile, "-") == 0) {
2817  ds = eNcbiLog_Stderr;
2818  logfile = NULL;
2819  }
2820  /* Set new destination */
2821  sx_Info->destination = ds;
2823  s_InitDestination(logfile);
2824 
2825  /* Read destination back, it can change */
2826  ds = sx_Info->destination;
2827 
2828  MT_UNLOCK;
2829  return ds;
2830 }
2831 
2832 
2833 extern ENcbiLog_Destination
2835  unsigned int port, const char* logsite)
2836 {
2837  char* logfile = NULL;
2838  MT_LOCK_API;
2839 
2840  /* NOTE:
2841  this is an internal version especially for ncbi_applog, so no need
2842  to close previous destination, befor setting new one.
2843  */
2844 
2845  /* Special case to redirect default logging output */
2846  if (ds == eNcbiLog_Default) {
2847  logfile = getenv("NCBI_CONFIG__LOG__FILE");
2848  if (logfile) {
2849  if (!*logfile ) {
2850  logfile = NULL;
2851  } else {
2852  if (strcmp(logfile, "-") == 0) {
2853  ds = eNcbiLog_Stderr;
2854  logfile = NULL;
2855  }
2856  }
2857  }
2858  }
2859  /* Set new destination */
2860  sx_Info->destination = ds;
2861  sx_Info->server_port = port;
2862  sx_Info->logsite = logsite;
2864  /* and force to initialize it */
2866  s_InitDestination(logfile);
2867  }
2868  ds = sx_Info->destination;
2869  MT_UNLOCK;
2870  return ds;
2871 }
2872 
2873 
2874 extern void NcbiLog_SetSplitLogFile(int /*bool*/ value)
2875 {
2876  MT_LOCK_API;
2878  MT_UNLOCK;
2879 }
2880 
2881 
2883 {
2884  MT_LOCK_API;
2885  sx_Info->pid = pid;
2886  MT_UNLOCK;
2887 }
2888 
2889 
2891 {
2893  MT_LOCK_API;
2894  ctx = s_GetContext();
2895  ctx->tid = tid;
2896  MT_UNLOCK;
2897 }
2898 
2899 
2901 {
2902  MT_LOCK_API;
2903  /* Enforce setting request id only after NcbiLog_AppRun() */
2904  if (sx_Info->state == eNcbiLog_NotSet ||
2906  TROUBLE_MSG("NcbiLog_SetRequestId() can be used after NcbiLog_AppRun() only");
2907  }
2908  sx_Info->rid = rid;
2909  MT_UNLOCK;
2910 }
2911 
2912 
2914 {
2915  TNcbiLog_Counter rid;
2916  MT_LOCK_API;
2917  rid = sx_Info->rid;
2918  MT_UNLOCK;
2919  return rid;
2920 }
2921 
2922 
2923 extern void NcbiLog_SetTime(time_t time_sec, unsigned long time_ns)
2924 {
2925  MT_LOCK_API;
2926  sx_Info->post_time.sec = time_sec;
2927  sx_Info->post_time.ns = time_ns;
2928  sx_Info->user_posting_time = (time_sec || time_ns ? 1 : 0);
2929  MT_UNLOCK;
2930 }
2931 
2932 
2933 extern void NcbiLog_SetHost(const char* host)
2934 {
2935  MT_LOCK_API;
2936  s_SetHost(host);
2937  MT_UNLOCK;
2938 }
2939 
2940 
2941 extern void NcbiLog_AppSetClient(const char* client)
2942 {
2943  MT_LOCK_API;
2944  s_SetClient((char*)sx_Info->client, client);
2945  MT_UNLOCK;
2946 }
2947 
2948 
2949 extern void NcbiLog_SetClient(const char* client)
2950 {
2952  MT_LOCK_API;
2953  ctx = s_GetContext();
2954  s_SetClient(ctx->client, client);
2955  ctx->is_client_set = 1;
2956  MT_UNLOCK;
2957 }
2958 
2959 
2960 extern void NcbiLog_AppSetSession(const char* session)
2961 {
2962  MT_LOCK_API;
2963  s_SetSession((char*)sx_Info->session, session);
2964  MT_UNLOCK;
2965 }
2966 
2967 
2968 extern char* NcbiLog_AppGetSession(void)
2969 {
2970  char* sid = NULL;
2971 
2972  MT_LOCK_API;
2973  /* Enforce calling this method after NcbiLog_AppStart() */
2974  if (sx_Info->state == eNcbiLog_NotSet ||
2976  TROUBLE_MSG("NcbiLog_AppGetSession() can be used after NcbiLog_AppStart() only");
2977  }
2978  if (sx_Info->session[0]) {
2979  sid = s_StrDup((char*)sx_Info->session);
2980  }
2981  MT_UNLOCK;
2982 
2983  return sid;
2984 }
2985 
2986 
2987 extern char* NcbiLog_GetSession(void)
2988 {
2990  char* sid = NULL;
2991 
2992  MT_LOCK_API;
2993  ctx = s_GetContext();
2994 
2995  if ( s_IsInsideRequest(ctx) ) {
2996  if (ctx->session[0]) {
2997  sid = s_StrDup(ctx->session);
2998  } else {
2999  if (sx_Info->session[0]) {
3000  sid = s_StrDup((char*)sx_Info->session);
3001  }
3002  }
3003  }
3004  MT_UNLOCK;
3005  return sid;
3006 }
3007 
3008 
3009 extern void NcbiLog_SetSession(const char* session)
3010 {
3012  MT_LOCK_API;
3013  ctx = s_GetContext();
3014  s_SetSession(ctx->session, session);
3015  ctx->is_session_set = 1;
3016  MT_UNLOCK;
3017 }
3018 
3019 
3020 extern void NcbiLog_AppNewSession(void)
3021 {
3022  char session[NCBILOG_SESSION_MAX+1];
3023  MT_LOCK_API;
3024  s_SetSession((char*)sx_Info->session, s_GenerateSID_Str(session));
3025  MT_UNLOCK;
3026 }
3027 
3028 
3029 extern void NcbiLog_NewSession(void)
3030 {
3031  char session[NCBILOG_SESSION_MAX+1];
3033  MT_LOCK_API;
3034  ctx = s_GetContext();
3035  s_SetSession(ctx->session, s_GenerateSID_Str(session));
3036  ctx->is_session_set = 1;
3037  MT_UNLOCK;
3038 }
3039 
3040 
3041 /* Log request/app-wide hit ID. See NcbiLog_GetNextSubHitID().
3042  */
3043 static void s_LogHitID(TNcbiLog_Context ctx, const char* hit_id)
3044 {
3045  SNcbiLog_Param params[2];
3046  assert(hit_id && hit_id[0]);
3047  int i = s_AddParamsPair(params, 0, "ncbi_phid", hit_id);
3048  params[i].key = NULL;
3049  params[i].value = NULL;
3050  s_Extra(ctx, params);
3051 }
3052 
3053 static void s_LogSubHitID(TNcbiLog_Context ctx, const char* subhit_id)
3054 {
3055  SNcbiLog_Param params[2];
3056  assert(subhit_id && subhit_id[0]);
3057  int i = s_AddParamsPair(params, 0, "issued_subhit", subhit_id);
3058  params[i].key = NULL;
3059  params[i].value = NULL;
3060  s_Extra(ctx, params);
3061 }
3062 
3063 
3064 extern void NcbiLog_AppSetHitID(const char* hit_id)
3065 {
3066  MT_LOCK_API;
3067  /* Enforce calling this method after NcbiLog_AppStart() */
3068  if (sx_Info->state != eNcbiLog_NotSet &&
3070  TROUBLE_MSG("NcbiLog_AppSetHitID() can be used before NcbiLog_App[Start/Run]() only");
3071  }
3072  s_SetHitID((char*)sx_Info->phid, hit_id);
3073  sx_Info->phid_inherit = 1;
3074  MT_UNLOCK;
3075 }
3076 
3077 
3078 extern void NcbiLog_SetHitID(const char* hit_id)
3079 {
3081 
3082  MT_LOCK_API;
3083  ctx = s_GetContext();
3084 
3085  /* Log new request-specific hit ID immediately if inside request
3086  or just save it for very next request.
3087  */
3088  if (hit_id && s_IsInsideRequest(ctx)) {
3089  /* if not the same */
3090  if ( !(ctx->phid[0] && strcmp(ctx->phid, hit_id) == 0) ) {
3091  s_LogHitID(ctx, hit_id);
3092  }
3093  } else {
3094  s_SetHitID(ctx->phid, hit_id);
3095  }
3096  MT_UNLOCK;
3097 }
3098 
3099 
3100 /* @deprecated */
3101 extern void NcbiLog_AppNewHitID(void)
3102 {
3103  return;
3104 }
3105 
3106 
3107 /* @deprecated */
3108 extern void NcbiLog_NewHitID(void)
3109 {
3110  return;
3111 }
3112 
3113 
3114 extern char* NcbiLog_AppGetHitID(void)
3115 {
3116  char* phid = NULL;
3117 
3118  MT_LOCK_API;
3119  /* Enforce calling this method after NcbiLog_AppStart() */
3120  if (sx_Info->state == eNcbiLog_NotSet ||
3122  TROUBLE_MSG("NcbiLog_AppGetHitID() can be used after NcbiLog_AppStart() only");
3123  }
3124  if (sx_Info->phid[0]) {
3125  phid = s_StrDup((char*)sx_Info->phid);
3126  }
3127  MT_UNLOCK;
3128  return phid;
3129 }
3130 
3131 
3132 extern char* NcbiLog_GetHitID(void)
3133 {
3135  char* phid = NULL;
3136 
3137  MT_LOCK_API;
3138  ctx = s_GetContext();
3139 
3140  if ( s_IsInsideRequest(ctx) ) {
3141  if (ctx->phid[0]) {
3142  phid = s_StrDup(ctx->phid);
3143  } else {
3144  if (sx_Info->phid[0] && sx_Info->phid_inherit) {
3145  phid = s_StrDup((char*)sx_Info->phid);
3146  }
3147  }
3148  }
3149  MT_UNLOCK;
3150  return phid;
3151 }
3152 
3153 
3154 /* Log request/app-wide hit ID. See NcbiLog_GetNextSubHitID().
3155  */
3156 static char* s_GetSubHitID(TNcbiLog_Context ctx, int /*bool*/ need_increment, const char* prefix)
3157 {
3158  char* hit_id = NULL;
3159  unsigned int* sub_id = NULL;
3160  char buf[5*NCBILOG_HITID_MAX]; /* use much bigger buffer to avoid overflow: prefix + 3*hitid + subid */
3161  size_t prefix_len = 0;
3162  int n;
3163 
3164  VERIFY_CATCH(sx_Info->phid[0]);
3165 
3166  // Check prefix length
3167  if (prefix) {
3168  prefix_len = strlen(prefix);
3169  VERIFY_CATCH(prefix_len < NCBILOG_HITID_MAX);
3170  }
3171 
3172  /* Select PHID to use */
3173  if (s_IsInsideRequest(ctx)) {
3174  if (ctx->phid[0]) {
3175  hit_id = ctx->phid;
3176  sub_id = &ctx->phid_sub_id;
3177  } else {
3178  /* No request-specific PHID, inherit app-wide value */
3180  hit_id = (char*)sx_Info->phid;
3181  sub_id = (unsigned int*)&sx_Info->phid_sub_id;
3182  }
3183  } else {
3184  hit_id = (char*)sx_Info->phid;
3185  sub_id = (unsigned int*)&sx_Info->phid_sub_id;
3186  }
3187 
3188  /* Generate sub hit ID */
3189  if (need_increment) {
3190  ++(*sub_id);
3191 
3192  /* Print issued sub hit ID number */
3193  if (*sub_id <= sx_Info->phid_sub_id_limit) {
3194  n = sprintf(buf, "%d", *sub_id);
3195  if (n <= 0) {
3196  return NULL; /* error */
3197  }
3198  s_LogSubHitID(ctx, buf);
3199  }
3200  }
3201 
3202  /* Generate sub hit ID string representation */
3203  n = sprintf(buf, "%s%s.%d", prefix ? prefix : "", hit_id, *sub_id);
3204  VERIFY_CATCH(n > 0 && n <= NCBILOG_HITID_MAX);
3205  return s_StrDup(buf);
3206 
3207 CATCH:
3208  return NULL; /* error */
3209 }
3210 
3211 
3212 extern char* NcbiLog_GetCurrentSubHitID(void)
3213 {
3215 }
3216 
3217 
3219 {
3221  char* subhit_id = NULL;
3222 
3223  MT_LOCK_API;
3224  ctx = s_GetContext();
3225 
3226  /* Enforce calling this method after NcbiLog_AppStart() */
3227  if (sx_Info->state == eNcbiLog_NotSet ||
3229  TROUBLE_MSG("NcbiLog_GetCurrentSubHitID() can be used after NcbiLog_AppStart() only");
3230  }
3231  subhit_id = s_GetSubHitID(ctx, 0, prefix);
3232 
3233  MT_UNLOCK;
3234  return subhit_id;
3235 }
3236 
3237 
3238 extern char* NcbiLog_GetNextSubHitID(void)
3239 {
3241 }
3242 
3243 
3244 extern char* NcbiLog_GetNextSubHitID_Prefix(const char* prefix)
3245 {
3247  char* subhit_id = NULL;
3248 
3249  MT_LOCK_API;
3250  ctx = s_GetContext();
3251 
3252  /* Enforce calling this method after NcbiLog_AppStart() */
3253  if (sx_Info->state == eNcbiLog_NotSet ||
3255  TROUBLE_MSG("NcbiLog_GetNextSubHitID() can be used after NcbiLog_AppStart() only");
3256  }
3257  subhit_id = s_GetSubHitID(ctx, 1, prefix);
3258 
3259  MT_UNLOCK;
3260  return subhit_id;
3261 }
3262 
3263 
3264 extern void NcbiLog_FreeMemory(void* ptr)
3265 {
3266  if (ptr) {
3267  free(ptr);
3268  }
3269 }
3270 
3271 
3273 {
3275  MT_LOCK_API;
3276  prev = sx_Info->post_level;
3277  sx_Info->post_level = sev;
3278  MT_UNLOCK;
3279  return prev;
3280 }
3281 
3282 
3284 {
3287  if (sx_IsInit == 1) {
3288  MT_LOCK_API;
3289  ctx = s_GetContext();
3290  /* Get application state (context-specific) */
3291  state = (ctx->state == eNcbiLog_NotSet) ? sx_Info->state : ctx->state;
3292  MT_UNLOCK;
3293  }
3294  return state;
3295 }
3296 
3297 
3298 /** Print "start" message.
3299  * We should print "start" message always, before any other message.
3300  * The NcbiLog_AppStart() is just a wrapper for this with checks and MT locking.
3301  */
3302 static void s_AppStart(TNcbiLog_Context ctx, const char* argv[])
3303 {
3304  size_t pos;
3305  char* buf;
3306 
3307  /* Try to get app-wide client from environment */
3308  if (!sx_Info->client[0]) {
3310  }
3311  /* Try to get app-wide session from environment */
3312  if (!sx_Info->session[0]) {
3314  }
3315  /* Try to get app-wide hit ID from environment */
3316  if (!sx_Info->phid[0]) {
3317  const char* ev = NcbiLogP_GetHitID_Env();
3318  if (ev) {
3319  s_SetHitID((char*)sx_Info->phid, ev);
3320  sx_Info->phid_inherit = 1;
3321  } else {
3322  /* Auto-generate new PHID (not-inherited by requests) */
3323  char phid_str[NCBILOG_HITID_MAX + 1];
3324  s_SetHitID((char*)sx_Info->phid, s_GenerateHitID_Str(phid_str));
3325  }
3326  }
3327 
3329  /* Prefix */
3330  buf = sx_Info->message;
3331  pos = s_PrintCommonPrefix(ctx);
3332  /* We already have current time in sx_Info->post_time */
3333  /* Save it into app_start_time. */
3336 
3337  VERIFY_CATCH(pos);
3338 
3339  /* Event name */
3340  pos += (size_t) sprintf(buf + pos, "%-13s", "start");
3341 
3342  /* Walk through list of arguments */
3343  if (argv) {
3344  int i;
3345  for (i = 0; argv[i] != NULL; ++i) {
3346  pos += (size_t) sprintf(buf + pos, " %s", argv[i]);
3347  }
3348  }
3349  /* Post a message */
3350  s_Post(ctx, eDiag_Log);
3351 
3352 CATCH:
3353  return;
3354 }
3355 
3356 
3357 extern void NcbiLog_AppStart(const char* argv[])
3358 {
3360  MT_LOCK_API;
3361  ctx = s_GetContext();
3362  s_AppStart(ctx, argv);
3363  MT_UNLOCK;
3364 }
3365 
3366 
3367 extern void NcbiLog_AppRun(void)
3368 {
3370  MT_LOCK_API;
3371  ctx = s_GetContext();
3372 
3373  /* Start app, if not started yet */
3376 
3377  /* Log extra parameters: app-wide PHID, host role and location */
3378 
3379  SNcbiLog_Param params[4];
3380  int i = 0;
3381  VERIFY(sx_Info->phid[0]);
3382 
3383  if (!sx_Info->host_role && !sx_Info->remote_logging) {
3385  }
3388  }
3389  i = s_AddParamsPair(params, i, "ncbi_phid", (char*)sx_Info->phid);
3390  i = s_AddParamsPair(params, i, "ncbi_role", sx_Info->host_role);
3391  i = s_AddParamsPair(params, i, "ncbi_location", sx_Info->host_location);
3392  params[i].key = NULL;
3393  params[i].value = NULL;
3394  s_Extra(ctx, params);
3395 
3396  MT_UNLOCK;
3397 }
3398 
3399 
3400 extern void NcbiLog_AppStop(int exit_status)
3401 {
3402  NcbiLogP_AppStop(exit_status, 0, -1);
3403 }
3404 
3405 
3406 extern void NcbiLog_AppStopSignal(int exit_status, int exit_signal)
3407 {
3408  NcbiLogP_AppStop(exit_status, exit_signal, -1);
3409 }
3410 
3411 
3412 extern void NcbiLogP_AppStop(int exit_status, int exit_signal, double execution_time)
3413 {
3415  size_t pos;
3416 
3417  MT_LOCK_API;
3418  ctx = s_GetContext();
3420 
3422  /* Prefix */
3423  pos = s_PrintCommonPrefix(ctx);
3424  VERIFY_CATCH(pos);
3425 
3426  if (execution_time < 0) {
3427  /* We already have current time in sx_Info->post_time */
3428  execution_time = s_DiffTime(sx_Info->app_start_time, sx_Info->post_time);
3429  }
3430  if ( exit_signal ) {
3431  sprintf(sx_Info->message + pos, "%-13s %d %.3f SIG=%d",
3432  "stop", exit_status, execution_time, exit_signal);
3433  } else {
3434  sprintf(sx_Info->message + pos, "%-13s %d %.3f",
3435  "stop", exit_status, execution_time);
3436  }
3437  /* Post a message */
3438  s_Post(ctx, eDiag_Log);
3439 
3440 CATCH:
3441  MT_UNLOCK;
3442 }
3443 
3444 
3445 
3447 {
3448  int n;
3449  size_t pos;
3450 
3453 
3454  /* Increase global request number, and save it in the context */
3455  sx_Info->rid++;
3456  ctx->rid = sx_Info->rid;
3457 
3458  /* Try to get client IP from environment, if not set by user */
3459  if (!ctx->is_client_set) {
3460  const char* ip = s_GetClient_Env();
3461  if (ip && *ip) {
3462  s_SetClient(ctx->client, ip);
3463  ctx->is_client_set = 1;
3464  }
3465  }
3466 
3467  /* Try to get session id from environment, or generate new one,
3468  if not set by user */
3469  if (!ctx->is_session_set) {
3470  const char* sid = NcbiLogP_GetSessionID_Env();
3471  if (sid && *sid) {
3472  s_SetSession(ctx->session, sid);
3473  } else {
3474  /* Unknown, create new session id */
3475  char session[NCBILOG_SESSION_MAX+1];
3476  s_SetSession(ctx->session, s_GenerateSID_Str(session));
3477  }
3478  ctx->is_session_set = 1;
3479  }
3480 
3481  /* Prefix */
3482  pos = s_PrintCommonPrefix(ctx);
3483  VERIFY_CATCH(pos);
3484 
3485  /* We already have current time in sx_Info->post_time */
3486  /* Save it into sx_RequestStartTime. */
3487  ctx->req_start_time.sec = sx_Info->post_time.sec;
3488  ctx->req_start_time.ns = sx_Info->post_time.ns;
3489 
3490  /* TODO:
3491  if "params" is NULL, parse and print $ENV{"QUERY_STRING"}
3492  */
3493 
3494  /* Event name */
3495  n = sprintf(sx_Info->message + pos, "%-13s ", "request-start");
3496  VERIFY_CATCH(n > 0);
3497  pos += (size_t)n;
3498 
3499  /* Return position in the message buffer */
3500  return pos;
3501 
3502 CATCH:
3503  /* error */
3504  return 0;
3505 }
3506 
3507 
3508 /** Print extra parameters for request start.
3509  * Automatically URL encode each key and value.
3510  * Return current position in the sx_Info->message buffer.
3511  */
3512 static size_t s_PrintReqStartExtraParams(size_t pos)
3513 {
3514  SNcbiLog_Param ext[3];
3515  size_t ext_idx = 0;
3516 
3517  memset((char*)ext, 0, sizeof(ext));
3518 
3519  /* Add host role */
3520  if (!sx_Info->host_role && !sx_Info->remote_logging) {
3522  }
3523  if (sx_Info->host_role && sx_Info->host_role[0]) {
3524  ext[ext_idx].key = "ncbi_role";
3525  ext[ext_idx].value = sx_Info->host_role;
3526  ext_idx++;
3527  }
3528 
3529  /* Add host location */
3532  }
3534  ext[ext_idx].key = "ncbi_location";
3535  ext[ext_idx].value = sx_Info->host_location;
3536  ext_idx++;
3537  }
3538 
3539  if (ext_idx) {
3540  pos = s_PrintParams(sx_Info->message, pos, ext);
3541  }
3542  return pos;
3543 }
3544 
3545 
3547 {
3549  size_t prev, pos = 0;
3550 
3551  MT_LOCK_API;
3552 
3553  ctx = s_GetContext();
3554  /* Common request info */
3555  pos = s_ReqStart(ctx);
3556  VERIFY_CATCH(pos);
3557 
3558  /* Print host role/location -- add it before users parameters */
3559  prev = pos;
3560  pos = s_PrintReqStartExtraParams(pos);
3561  if (prev != pos && params && params->key && params->key[0] && pos < NCBILOG_ENTRY_MAX) {
3562  sx_Info->message[pos++] = '&';
3563  }
3564  /* User request parameters */
3565  pos = s_PrintParams(sx_Info->message, pos, params);
3566  /* Post a message */
3567  s_Post(ctx, eDiag_Log);
3568 
3569 CATCH:
3570  MT_UNLOCK;
3571 }
3572 
3573 
3574 extern void NcbiLogP_ReqStartStr(const char* params)
3575 {
3577  size_t prev, pos = 0;
3578 
3579  MT_LOCK_API;
3580 
3581  ctx = s_GetContext();
3582  /* Common request info */
3583  pos = s_ReqStart(ctx);
3584  VERIFY_CATCH(pos);
3585 
3586  /* Print host role/location */
3587  prev = pos;
3588  pos = s_PrintReqStartExtraParams(pos);
3589  if (prev != pos && params && params[0] && pos < NCBILOG_ENTRY_MAX) {
3590  sx_Info->message[pos++] = '&';
3591  }
3592  /* Parameters */
3593  pos = s_PrintParamsStr(sx_Info->message, pos, params);
3594  /* Post a message */
3595  s_Post(ctx, eDiag_Log);
3596 
3597 CATCH:
3598  MT_UNLOCK;
3599 }
3600 
3601 
3602 extern void NcbiLog_ReqRun(void)
3603 {
3605  MT_LOCK_API;
3606  ctx = s_GetContext();
3607 
3610 
3611  /* Always log PHID on the request start.
3612  If PHID is not set on application or request level, then new PHID
3613  will be generated and set for the request.
3614  */
3615  if (!ctx->phid[0]) {
3616  char phid_str[NCBILOG_HITID_MAX + 1];
3617  /* Usually we should always have app-wide PHID, but not
3618  in the case of ncbi_applog utility */
3619  /* VERIFY(sx_Info->phid[0]); */
3620  if (sx_Info->phid[0] && sx_Info->phid_inherit) {
3621  /* Just log app-wide PHID, do not set it as request specific
3622  to allow NcbiLog_GetNextSubHitID() work correctly and
3623  use app-wide sub hits.
3624  */
3625  s_LogHitID(ctx, (char*)sx_Info->phid);
3626  MT_UNLOCK;
3627  return;
3628  }
3629  /* Generate and set new request-specific PHID */
3630  s_SetHitID(ctx->phid, s_GenerateHitID_Str(phid_str));
3631  }
3632  s_LogHitID(ctx, ctx->phid);
3633 
3634  MT_UNLOCK;
3635 }
3636 
3637 
3638 extern void NcbiLog_ReqStop(int status, size_t bytes_rd, size_t bytes_wr)
3639 {
3641  size_t pos;
3642  double timespan;
3643 
3644  MT_LOCK_API;
3645  ctx = s_GetContext();
3648 
3649  /* Prefix */
3650  pos = s_PrintCommonPrefix(ctx);
3651  VERIFY_CATCH(pos);
3652 
3653  /* We already have current time in sx_Info->post_time */
3654  timespan = s_DiffTime(ctx->req_start_time, sx_Info->post_time);
3655  sprintf(sx_Info->message + pos, "%-13s %d %.3f %lu %lu",
3656  "request-stop", status, timespan,
3657  (unsigned long)bytes_rd, (unsigned long)bytes_wr);
3658  /* Post a message */
3659  s_Post(ctx, eDiag_Log);
3660  /* Reset state */
3662 
3663  /* Reset request, client, session and hit ID */
3664  ctx->rid = 0;
3665  ctx->client[0] = '\0'; ctx->is_client_set = 0;
3666  ctx->session[0] = '\0'; ctx->is_session_set = 0;
3667  ctx->phid[0] = '\0'; ctx->phid_sub_id = 0;
3668 
3669 CATCH:
3670  MT_UNLOCK;
3671 }
3672 
3673 
3674 static void s_Extra(TNcbiLog_Context ctx, const SNcbiLog_Param* params)
3675 {
3676  size_t pos;
3677  char* buf;
3678 
3679  /* Prefix */
3680  buf = sx_Info->message;
3681  pos = s_PrintCommonPrefix(ctx);
3682  VERIFY_CATCH(pos);
3683  /* Event name */
3684  pos += (size_t) sprintf(buf + pos, "%-13s ", "extra");
3685  /* Parameters */
3686  pos = s_PrintParams(buf, pos, params);
3687  /* Post a message */
3688  s_Post(ctx, eDiag_Log);
3689 
3690 CATCH:
3691  return;
3692 }
3693 
3694 
3695 static void s_ExtraStr(TNcbiLog_Context ctx, const char* params)
3696 {
3697  size_t pos;
3698  char* buf;
3699 
3700  /* Prefix */
3701  buf = sx_Info->message;
3702  pos = s_PrintCommonPrefix(ctx);
3703  VERIFY_CATCH(pos);
3704  /* Event name */
3705  pos += (size_t) sprintf(buf + pos, "%-13s ", "extra");
3706  /* Parameters */
3707  pos = s_PrintParamsStr(buf, pos, params);
3708  /* Post a message */
3709  s_Post(ctx, eDiag_Log);
3710 
3711 CATCH:
3712  return;
3713 }
3714 
3715 
3716 extern void NcbiLog_Extra(const SNcbiLog_Param* params)
3717 {
3719  MT_LOCK_API;
3720  ctx = s_GetContext();
3722  s_Extra(ctx, params);
3723  MT_UNLOCK;
3724 }
3725 
3726 
3727 extern void NcbiLogP_ExtraStr(const char* params)
3728 {
3730  MT_LOCK_API;
3731  ctx = s_GetContext();
3733  s_ExtraStr(ctx, params);
3734  MT_UNLOCK;
3735 }
3736 
3737 
3738 extern void NcbiLog_Perf(int status, double timespan, const SNcbiLog_Param* params)
3739 {
3741  size_t pos, pos_prev;
3742  char* buf;
3743  char* hit_id = NULL;
3744 
3745  MT_LOCK_API;
3746  ctx = s_GetContext();
3748 
3749  /* Prefix */
3750  buf = sx_Info->message;
3751  pos = s_PrintCommonPrefix(ctx);
3752  VERIFY_CATCH(pos);
3753 
3754  /* Print event name, status and timespan */
3755  pos += (size_t) sprintf(buf + pos, "%-13s %d %f ", "perf", status, timespan);
3756 
3757  /* Parameters */
3758  pos_prev = pos;
3759  pos = s_PrintParams(buf, pos, params);
3760 
3761  /* Add PHID if known */
3762  if (s_IsInsideRequest(ctx)) {
3763  hit_id = ctx->phid[0] ? ctx->phid : (char*)sx_Info->phid;
3764  } else {
3765  hit_id = (char*)sx_Info->phid;
3766  }
3767  if (hit_id) {
3768  /* need to add '&' ? */
3769  if ((pos > pos_prev) && (pos < NCBILOG_ENTRY_MAX - 1)) {
3770  buf[pos++] = '&';
3771  }
3772  pos = s_PrintParamsPair(buf, pos, "ncbi_phid", hit_id);
3773  }
3774  /* Post a message */
3775  s_Post(ctx, eDiag_Perf);
3776 
3777 CATCH:
3778  MT_UNLOCK;
3779 }
3780 
3781 
3782 extern void NcbiLogP_PerfStr(int status, double timespan, const char* params)
3783 {
3785  size_t pos, pos_prev;
3786  char* buf;
3787  char* hit_id = NULL;
3788 
3789  MT_LOCK_API;
3790  ctx = s_GetContext();
3792 
3793  /* Prefix */
3794  buf = sx_Info->message;
3795  pos = s_PrintCommonPrefix(ctx);
3796  VERIFY_CATCH(pos);
3797 
3798  /* Print event name, status and timespan */
3799  pos += (size_t) sprintf(buf + pos, "%-13s %d %f ", "perf", status, timespan);
3800 
3801  /* Parameters */
3802  pos_prev = pos;
3803  pos = s_PrintParamsStr(buf, pos, params);
3804 
3805  /* Add PHID if known */
3806  if (s_IsInsideRequest(ctx)) {
3807  hit_id = ctx->phid[0] ? ctx->phid : (char*)sx_Info->phid;
3808  } else {
3809  hit_id = (char*)sx_Info->phid;
3810  }
3811  if (hit_id && hit_id[0]) {
3812  /* need to add '&' ? */
3813  if ((pos > pos_prev) && (pos < NCBILOG_ENTRY_MAX - 1)) {
3814  buf[pos++] = '&';
3815  }
3816  pos = s_PrintParamsPair(buf, pos, "ncbi_phid", hit_id);
3817  }
3818  /* Post a message */
3819  s_Post(ctx, eDiag_Perf);
3820 
3821 CATCH:
3822  MT_UNLOCK;
3823 }
3824 
3825 
3826 extern void NcbiLog_Trace(const char* msg)
3827 {
3828  s_PrintMessage(eNcbiLog_Trace, msg, 0 /*false*/);
3829 }
3830 
3831 extern void NcbiLog_Info(const char* msg)
3832 {
3833  s_PrintMessage(eNcbiLog_Info, msg, 0 /*false*/);
3834 }
3835 
3836 extern void NcbiLog_Warning(const char* msg)
3837 {
3838  s_PrintMessage(eNcbiLog_Warning, msg, 0 /*false*/);
3839 }
3840 
3841 extern void NcbiLog_Error(const char* msg)
3842 {
3843  s_PrintMessage(eNcbiLog_Error, msg, 0 /*false*/);
3844 }
3845 
3846 void NcbiLog_Critical(const char* msg)
3847 {
3848  s_PrintMessage(eNcbiLog_Critical, msg, 0 /*false*/);
3849 }
3850 
3851 extern void NcbiLog_Fatal(const char* msg)
3852 {
3853  s_PrintMessage(eNcbiLog_Fatal, msg, 0 /*false*/);
3854 }
3855 
3856 extern void NcbiLog_Note(ENcbiLog_Severity severity, const char* msg)
3857 {
3858  s_PrintMessage(severity, msg, 1 /*true*/);
3859 }
3860 
3861 
3862 extern void NcbiLogP_Raw(const char* line)
3863 {
3864  assert(line);
3865  NcbiLogP_Raw2(line, strlen(line));
3866 }
3867 
3868 extern void NcbiLogP_Raw2(const char* line, size_t len)
3869 {
3871 #if NCBILOG_USE_FILE_DESCRIPTORS
3872  size_t n;
3873 #else
3874  int n;
3875 #endif
3876 
3877  VERIFY(line);
3878  VERIFY(line[len] == '\0');
3880 
3881  MT_LOCK_API;
3883  MT_UNLOCK;
3884  return;
3885  }
3886  /* Reopen logging files, if necessary */
3888  /* Destination can be disabled on reopening, so check again */
3890  MT_UNLOCK;
3891  return;
3892  }
3893  f = sx_Info->file_log;
3894 
3895  switch (sx_Info->destination) {
3896  case eNcbiLog_Default:
3897  case eNcbiLog_Stdlog:
3898  case eNcbiLog_Cwd:
3899  case eNcbiLog_File:
3900  /* Try to get type of the line to redirect output into correct log file */
3901  {
3902  const char* start = line + NCBILOG_ENTRY_MIN - 1;
3903  const char* ptr = strstr(start, (char*)sx_Info->appname);
3904 
3905  if (!ptr || (ptr - start > NCBILOG_APPNAME_MAX)) {
3906  break;
3907  }
3908  ptr += strlen((char*)sx_Info->appname) + 1;
3909 
3910  if (len > (size_t)(ptr - line) + 5) {
3911  if (strncmp(ptr, "perf", 4) == 0) {
3912  f = sx_Info->file_perf;
3913  } else
3914  if (strncmp(ptr, "Trace", 5) == 0 ||
3915  strncmp(ptr, "Info" , 4) == 0) {
3916  f = sx_Info->file_trace;
3917  }
3918  }
3919  if (f == kInvalidFileHandle) {
3920  /* Warning, Error, Critical, Fatal, or any other line */
3921  f = sx_Info->file_err;
3922  }
3923  }
3924  break;
3925  case eNcbiLog_Stdout:
3926  case eNcbiLog_Stderr:
3927  case eNcbiLog_Disable:
3928  /* Nothing to do here -- all logging going to the same stream sx_Info->file_log */
3929  break;
3930  }
3931 
3933 
3934 #if NCBILOG_USE_FILE_DESCRIPTORS
3935  VERIFY_CATCH(len < NCBILOG_ENTRY_MAX); /* account +1 for '\n' */
3936  memcpy(sx_Info->message, line, len);
3937  sx_Info->message[len] = '\n';
3938  /* should be a single write */
3939  n = s_Write(f, sx_Info->message, len + 1);
3940  VERIFY(n == len + 1);
3941  /* fdatasync(f); */
3942 #else
3943  n = fprintf(f, "%s\n", line);
3944  VERIFY(n > 0);
3945  fflush(f);
3946 #endif
3947 
3948 CATCH:
3949  MT_UNLOCK;
3950 }
3951 
3952 
3954 {
3955  int n;
3956  #define kIdBufSize 128
3957  char buf[kIdBufSize];
3958  int old_guid_hi, old_guid_lo;
3960 
3961  MT_LOCK_API;
3962 
3963  ctx = s_GetContext();
3964  TNcbiLog_PID old_pid = sx_PID;
3965 
3966 #if defined(NCBI_OS_UNIX)
3967  TNcbiLog_PID new_pid = (TNcbiLog_PID)getpid();
3968 #elif defined(NCBI_OS_MSWIN)
3969  TNcbiLog_PID new_pid = GetCurrentProcessId();
3970 #endif
3971  if (old_pid == new_pid) {
3972  /* Do not perform any actions in the parent process. */
3973  MT_UNLOCK;
3974  return;
3975  }
3976  /* -- Child process -- */
3977 
3978  sx_PID = new_pid;
3979 
3980  /* Update GUID to match the new PID */
3981  old_guid_hi = (int)((sx_Info->guid >> 32) & 0xFFFFFFFF);
3982  old_guid_lo = (int)(sx_Info->guid & 0xFFFFFFFF);
3983  sx_Info->guid = s_CreateUID();
3984 
3985  /* Reset tid for the current context */
3986  ctx->tid = s_GetTID();
3987 
3990  }
3992  /* Forcedly reset state to allow starting sequince */
3994  s_AppStart(ctx, NULL);
3996  }
3997 
3998  /* Log ID changes */
3999  n = sprintf(buf,
4000  "action=fork&parent_guid=%08X%08X&parent_pid=%05" NCBILOG_UINT8_FORMAT_SPEC,
4001  old_guid_hi, old_guid_lo, old_pid);
4002  VERIFY(n > 0 && n < kIdBufSize);
4003  s_ExtraStr(ctx, buf);
4004 
4006  /* Also, log app-wide hit ID for the new process as well */
4007  VERIFY(sx_Info->phid[0]);
4008  s_LogHitID(ctx, (char*)sx_Info->phid);
4009  }
4010 
4011  MT_UNLOCK;
4012 }
4013 
4014 
4015 
4016 /******************************************************************************
4017  * Logging setup functions --- for internal use only
4018  */
4019 
4021 {
4022  return (TNcbiLog_Info*)sx_Info;
4023 }
4024 
4026 {
4027  return s_GetContext();
4028 }
4029 
4030  extern int NcbiLogP_DisableChecks(int /*bool*/ disable)
4031  {
4032  int current = sx_DisableChecks;
4033  sx_DisableChecks = disable;
4034  return current;
4035  }
#define static
void(*)(CSeq_entry_Handle seh, IWorkbench *wb, const CSerialObject &obj) handler
static uch flags
int close(int fd)
Definition: connection.cpp:45
static const char fp[]
Definition: des.c:87
static const char ip[]
Definition: des.c:75
static void cleanup(void)
Definition: ct_dynamic.c:30
CS_CONTEXT * ctx
Definition: t0006.c:12
static const struct name_t names[]
static DLIST_TYPE *DLIST_NAME() prev(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
Definition: dlist.tmpl.h:61
static const char * str(char *buf, int n)
Definition: stats.c:84
static const char location[]
Definition: config.c:97
#define NULL
Definition: ncbistd.hpp:225
char * NcbiLog_AppGetSession(void)
Get session ID (SID) for the whole application.
Definition: ncbi_c_log.c:2968
void NcbiLog_InitMT(const char *appname)
Version of NcbiLog_Init with default MT lock implementation.
Definition: ncbi_c_log.c:2547
TNcbiLog_UInt8 TNcbiLog_TID
Definition: ncbi_c_log.h:304
ENcbiLog_Destination NcbiLog_SetDestinationFile(const char *logfile_base)
Variant of NcbiLog_SetDestination for logging to a specific file (eNcbiLog_File).
Definition: ncbi_c_log.c:2801
void NcbiLog_MTLock_Delete(TNcbiLog_MTLock lock)
Call cleanup action on the handler, then destroy it.
Definition: ncbi_c_log.c:363
void NcbiLog_AppSetClient(const char *client)
Set client for the whole application.
Definition: ncbi_c_log.c:2941
void NcbiLog_AppSetSession(const char *session)
Set session ID (SID) for the whole application.
Definition: ncbi_c_log.c:2960
ENcbiLog_AppState NcbiLog_GetState(void)
Get current logging execution state (context and thread specific).
Definition: ncbi_c_log.c:3283
void NcbiLog_AppStopSignal(int exit_status, int exit_signal)
The same as NcbiLog_AppStop(), except it also accepts a signal number, if application exited due to a...
Definition: ncbi_c_log.c:3406
void NcbiLog_InitForAttachedContextST(const char *appname)
Version of NcbiLog_InitForAttachedContext() intended to use in single-threaded applications.
Definition: ncbi_c_log.c:2588
void NcbiLog_AppStop(int exit_status)
Should be called immediately prior to the application exit.
Definition: ncbi_c_log.c:3400
char * NcbiLog_GetCurrentSubHitID_Prefix(const char *prefix)
Get the last generated sub-hit ID.
Definition: ncbi_c_log.c:3218
ENcbiLog_MTLock_Action
The action passed to user defined MT lock handler.
Definition: ncbi_c_log.h:152
void NcbiLog_Info(const char *msg)
Writes a message to the <appname>.trace file at level 'INFO'.
Definition: ncbi_c_log.c:3831
void NcbiLog_UpdateOnFork(TNcbiLog_OnForkFlags flags)
Update logging internal information after fork().
Definition: ncbi_c_log.c:3953
void NcbiLog_Extra(const SNcbiLog_Param *params)
Can be called at any time.
Definition: ncbi_c_log.c:3716
const char * value
Definition: ncbi_c_log.h:277
const char * NcbiLog_GetHostRole(void)
Get host role string.
Definition: ncbi_c_log.c:630
void NcbiLog_SetHitID(const char *hit_id)
Set hit ID (HID, a.k.a.
Definition: ncbi_c_log.c:3078
TNcbiLog_Context NcbiLog_Context_Create(void)
Create new thread-specific logging context object.
Definition: ncbi_c_log.c:2644
ENcbiLog_Destination NcbiLog_SetDestination(ENcbiLog_Destination ds)
Set up diagnostics destination.
Definition: ncbi_c_log.c:2753
void NcbiLog_AppNewSession(void)
Auto-generate and then set brand-new application-wide session ID (SID).
Definition: ncbi_c_log.c:3020
void NcbiLog_ReqStart(const SNcbiLog_Param *params)
Should be called once application startup is complete, before any request processing code is run.
Definition: ncbi_c_log.c:3546
const char * NcbiLog_GetHostName(void)
Get host name.
Definition: ncbi_c_log.c:573
void NcbiLog_Error(const char *msg)
Writes a message to the <appname>.err log at level 'ERROR'.
Definition: ncbi_c_log.c:3841
void NcbiLog_Context_Destroy(TNcbiLog_Context ctx)
Destroy context structure.
Definition: ncbi_c_log.c:2681
void NcbiLog_InitST(const char *appname)
Version of NcbiLog_Init to use in single-threaded applications.
Definition: ncbi_c_log.c:2554
void NcbiLog_SetRequestId(TNcbiLog_Counter rid)
Set current request ID (RID).
Definition: ncbi_c_log.c:2900
int NcbiLog_Default_MTLock_Handler(void *user_data_UNUSED, ENcbiLog_MTLock_Action action)
Default implementation of simple MT locking callback.
Definition: ncbi_c_log.c:256
TNcbiLog_Counter NcbiLog_GetRequestId(void)
Get current request ID (RID).
Definition: ncbi_c_log.c:2913
ENcbiLog_AppState
Application execution states shown in the std prefix.
Definition: ncbi_c_log.h:995
void NcbiLog_SetProcessId(TNcbiLog_PID pid)
Set process ID (PID).
Definition: ncbi_c_log.c:2882
TNcbiLog_UInt8 TNcbiLog_Counter
Definition: ncbi_c_log.h:305
void NcbiLog_SetHost(const char *host)
Set the host name.
Definition: ncbi_c_log.c:2933
void NcbiLog_Context_Detach(void)
Detach logging context object from the C Logging API.
Definition: ncbi_c_log.c:2668
ENcbiLog_Destination
Where to write the application's diagnostics to.
Definition: ncbi_c_log.h:246
void NcbiLog_NewSession(void)
Auto-generate and then set brand-new session ID (SID) for the request.
Definition: ncbi_c_log.c:3029
char * NcbiLog_GetCurrentSubHitID(void)
Definition: ncbi_c_log.c:3212
void NcbiLog_NewHitID(void)
Definition: ncbi_c_log.c:3108
ENcbiLog_Severity NcbiLog_SetPostLevel(ENcbiLog_Severity sev)
Set new posting severity threshold.
Definition: ncbi_c_log.c:3272
void NcbiLog_Destroy(void)
Destroy NcbiLog API.
Definition: ncbi_c_log.c:2602
char * NcbiLog_GetNextSubHitID(void)
Definition: ncbi_c_log.c:3238
char * NcbiLog_GetSession(void)
Get sessio ID (SID) for the request.
Definition: ncbi_c_log.c:2987
ENcbiLog_Severity
Severity level for the posted diagnostics.
Definition: ncbi_c_log.h:261
TNcbiLog_UInt8 TNcbiLog_PID
Process, thread and counter types.
Definition: ncbi_c_log.h:303
void NcbiLog_AppStart(const char *argv[])
Should be called as soon as possible during application initialization.
Definition: ncbi_c_log.c:3357
void NcbiLog_ReqStop(int status, size_t bytes_rd, size_t bytes_wr)
Should be called once request processing is complete.
Definition: ncbi_c_log.c:3638
void NcbiLog_SetSplitLogFile(int value)
Set split log files flag.
Definition: ncbi_c_log.c:2874
unsigned __int64 TNcbiLog_UInt8
Definition: ncbi_c_log.h:290
void NcbiLog_FreeMemory(void *ptr)
Free memory allocated inside the C logging API.
Definition: ncbi_c_log.c:3264
void NcbiLog_Perf(int status, double timespan, const SNcbiLog_Param *params)
Can be called at any time.
Definition: ncbi_c_log.c:3738
void NcbiLog_SetClient(const char *client)
Set client for the request.
Definition: ncbi_c_log.c:2949
void NcbiLog_Warning(const char *msg)
Writes a message to the <appname>.err log at level 'WARNING'.
Definition: ncbi_c_log.c:3836
int TNcbiLog_OnForkFlags
Binary OR of "ENcbiLog_OnForkAction".
Definition: ncbi_c_log.h:455
char * NcbiLog_AppGetHitID(void)
Get hit ID (HID, a.k.a.
Definition: ncbi_c_log.c:3114
ENcbiLog_MTLock_Ownership
Type of ownership for MT lock handle.
Definition: ncbi_c_log.h:162
void NcbiLog_SetThreadId(TNcbiLog_TID tid)
Set thread ID (TID).
Definition: ncbi_c_log.c:2890
void NcbiLog_Fatal(const char *msg)
Writes a message to the <appname>.err log at level 'FATAL' and then terminate the application.
Definition: ncbi_c_log.c:3851
struct SNcbiLog_Context_tag * TNcbiLog_Context
Definition: ncbi_c_log.h:311
void NcbiLog_InitForAttachedContext(const char *appname)
Version of NcbiLog_Init to use with NcbiLog_Context_* functions only.
Definition: ncbi_c_log.c:2560
void NcbiLog_Critical(const char *msg)
Writes a message to the <appname>.err log at level 'CRITICAL'.
Definition: ncbi_c_log.c:3846
void NcbiLog_Trace(const char *msg)
Writes a message to the <appname>.trace file at level 'TRACE'.
Definition: ncbi_c_log.c:3826
char * NcbiLog_GetHitID(void)
Get hit ID (HID, a.k.a.
Definition: ncbi_c_log.c:3132
int NcbiLog_Context_Attach(TNcbiLog_Context ctx)
Attach logging context object to the C Logging API.
Definition: ncbi_c_log.c:2655
char * NcbiLog_GetNextSubHitID_Prefix(const char *prefix)
Generate a sub-hit ID based on the currently effective (whether it's request-specific or application-...
Definition: ncbi_c_log.c:3244
void NcbiLog_Destroy_Thread(void)
Destroy thread-specific NcbiLog API information.
Definition: ncbi_c_log.c:2594
void NcbiLog_ReqRun(void)
Should be called once request processing initialization is complete.
Definition: ncbi_c_log.c:3602
int(* FNcbiLog_MTLock_Handler)(void *user_data, ENcbiLog_MTLock_Action action)
MT locking callback.
Definition: ncbi_c_log.h:187
const char * key
Definition: ncbi_c_log.h:276
void NcbiLog_AppRun(void)
Should be called after the application is initialized and before its main part.
Definition: ncbi_c_log.c:3367
__int64 TNcbiLog_Int8
Big integer type.
Definition: ncbi_c_log.h:289
TNcbiLog_MTLock NcbiLog_MTLock_Create(void *user_data, FNcbiLog_MTLock_Handler handler)
Create new MT lock.
Definition: ncbi_c_log.c:348
void NcbiLog_SetTime(time_t time_sec, unsigned long time_ns)
Set the posting date and time.
Definition: ncbi_c_log.c:2923
const char * NcbiLog_GetHostLocation(void)
Get host location string.
Definition: ncbi_c_log.c:648
void NcbiLog_AppSetHitID(const char *hit_id)
Set hit ID (HID, a.k.a.
Definition: ncbi_c_log.c:3064
#define NCBILOG_UINT8_FORMAT_SPEC
Definition: ncbi_c_log.h:292
void NcbiLog_Init(const char *appname, TNcbiLog_MTLock mt_lock, ENcbiLog_MTLock_Ownership mt_lock_ownership)
Initializing NcbiLog API.
Definition: ncbi_c_log.c:2520
void NcbiLog_AppNewHitID(void)
Definition: ncbi_c_log.c:3101
void NcbiLog_Note(ENcbiLog_Severity severity, const char *msg)
Writes a message using "Note[X]" notation for severity.
Definition: ncbi_c_log.c:3856
void NcbiLog_SetSession(const char *session)
Set session ID (SID) for the request.
Definition: ncbi_c_log.c:3009
@ eNcbiLog_MT_Lock
Lock.
Definition: ncbi_c_log.h:154
@ eNcbiLog_MT_Unlock
Unlock.
Definition: ncbi_c_log.h:155
@ eNcbiLog_MT_Init
Init the locker (call first)
Definition: ncbi_c_log.h:153
@ eNcbiLog_MT_Destroy
Unlock and cleanup (call last)
Definition: ncbi_c_log.h:156
@ fNcbiLog_OnFork_ResetTimer
Reset execution timer.
Definition: ncbi_c_log.h:450
@ fNcbiLog_OnFork_PrintStart
Log app-start.
Definition: ncbi_c_log.h:449
@ eNcbiLog_RequestEnd
RE.
Definition: ncbi_c_log.h:1002
@ eNcbiLog_NotSet
Reserved value, never used in messages.
Definition: ncbi_c_log.h:996
@ eNcbiLog_RequestBegin
RB.
Definition: ncbi_c_log.h:1000
@ eNcbiLog_AppEnd
PE.
Definition: ncbi_c_log.h:999
@ eNcbiLog_Request
R.
Definition: ncbi_c_log.h:1001
@ eNcbiLog_AppRun
P.
Definition: ncbi_c_log.h:998
@ eNcbiLog_AppBegin
PB.
Definition: ncbi_c_log.h:997
@ eNcbiLog_Disable
Don't write it anywhere.
Definition: ncbi_c_log.h:255
@ eNcbiLog_Cwd
Try .
Definition: ncbi_c_log.h:251
@ eNcbiLog_Stdlog
Try /log/<*>/<appname>.log; fallback to .
Definition: ncbi_c_log.h:249
@ eNcbiLog_File
To specific file, see NcbiLog_SetDestinationFile()
Definition: ncbi_c_log.h:252
@ eNcbiLog_Stderr
To standard error stream.
Definition: ncbi_c_log.h:254
@ eNcbiLog_Stdout
To standard output stream.
Definition: ncbi_c_log.h:253
@ eNcbiLog_Default
Try /log/<*>/<appname>.log; fallback to STDERR.
Definition: ncbi_c_log.h:247
@ eNcbiLog_Info
Informational message.
Definition: ncbi_c_log.h:263
@ eNcbiLog_Fatal
Fatal error – guarantees exit (or abort)
Definition: ncbi_c_log.h:267
@ eNcbiLog_Warning
Warning message.
Definition: ncbi_c_log.h:264
@ eNcbiLog_Trace
Trace message.
Definition: ncbi_c_log.h:262
@ eNcbiLog_Error
Error message.
Definition: ncbi_c_log.h:265
@ eNcbiLog_Critical
Critical error message.
Definition: ncbi_c_log.h:266
@ eNcbiLog_MT_TakeOwnership
NcbiLog API takes ownership of MT lock.
Definition: ncbi_c_log.h:164
@ eNcbiLog_MT_NoOwnership
No ownership relationship.
Definition: ncbi_c_log.h:163
@ eDiag_Trace
Trace message.
Definition: ncbidiag.hpp:657
#define FILENAME_MAX
Definition: ncbifile.hpp:94
HANDLE TFileHandle
Definition: ncbifile.hpp:115
unsigned int mode_t
Definition: ncbifile.hpp:84
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
exit(2)
FILE * file
char * buf
int i
yy_size_t n
int len
mdb_mode_t mode
Definition: lmdb++.h:38
const struct ncbi::grid::netcache::search::fields::SIZE size
const struct ncbi::grid::netcache::search::fields::KEY key
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
int strncmp(const char *str1, const char *str2, size_t count)
Definition: odbc_utils.hpp:133
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
static TNcbiLog_UInt8 s_CreateUID(void)
Create unique process ID.
Definition: ncbi_c_log.c:708
static volatile pthread_key_t sx_Tls
Definition: ncbi_c_log.c:385
static volatile TNcbiLog_Info * sx_Info
Definition: ncbi_c_log.c:184
TNcbiLog_Context NcbiLogP_GetContextPtr(void)
Definition: ncbi_c_log.c:4025
int NcbiLogP_DisableChecks(int disable)
Enable/disable internal checks (enabled by default) Used by ncbi_applog.
Definition: ncbi_c_log.c:4030
#define kMTLock_magic_number
Definition: ncbi_c_log.c:312
#define DIR_SEPARATOR
Definition: ncbi_c_log.c:144
static char * s_GetSubHitID(TNcbiLog_Context ctx, int need_increment, const char *prefix)
Definition: ncbi_c_log.c:3156
static const char * s_ReadFileString(const char *filename)
Read first string from specified file.
Definition: ncbi_c_log.c:604
static void s_TlsDestroy(void)
Definition: ncbi_c_log.c:411
static const char * s_ConcatPathEx(const char *p1, size_t p1_len, const char *p2, size_t p2_len, char *dst, size_t dst_size)
Concatenate two parts of the path for the current OS.
Definition: ncbi_c_log.c:529
static const char * s_GetToolkitRCLogLocation()
Determine logs location on the base of TOOLKITRC_FILE.
Definition: ncbi_c_log.c:1317
static const unsigned char sx_EncodeTable[256][4]
Definition: ncbi_c_log.c:973
#define TROUBLE
Definition: ncbi_c_log.c:87
void NcbiLogP_Raw(const char *line)
Post already prepared line in applog format to the applog.
Definition: ncbi_c_log.c:3862
static int s_IsInsideRequest(TNcbiLog_Context ctx)
Definition: ncbi_c_log.c:1921
const char * NcbiLogP_GetHitID_Env(void)
This routine is called during start up and again in NcbiLog_ReqStart().
Definition: ncbi_c_log.c:931
#define TROUBLE_MSG(msg)
Definition: ncbi_c_log.c:88
const char * NcbiLogP_GenerateHitID(char *buf, size_t n, TNcbiLog_UInt8 uid)
Generate new Hit ID string.
Definition: ncbi_c_log.c:2023
static double s_DiffTime(const STime time_start, const STime time_end)
Get time difference, time_end >- time_start.
Definition: ncbi_c_log.c:806
const char * NcbiLogP_GenerateSID(char *buf, size_t n, TNcbiLog_UInt8 uid)
Generate new SID string.
Definition: ncbi_c_log.c:2037
ENcbiLog_Destination NcbiLogP_SetDestination(ENcbiLog_Destination ds, unsigned int port, const char *logsite)
Variant of NcbiLog_SetDestination.
Definition: ncbi_c_log.c:2834
static void * s_TlsGetValue(void)
Definition: ncbi_c_log.c:425
static volatile int sx_DisableChecks
Definition: ncbi_c_log.c:181
#define MT_LOCK_API
Definition: ncbi_c_log.c:462
static const char * sx_AppStateStr[]
Definition: ncbi_c_log.c:2162
#define CHECK_APP_START(ctx)
Definition: ncbi_c_log.c:474
static pthread_mutex_t sx_MT_handle
Definition: ncbi_c_log.c:250
static char * s_GenerateSID_Str(char *dst)
Definition: ncbi_c_log.c:1963
static void s_Init(const char *appname)
Definition: ncbi_c_log.c:2445
static TNcbiLog_Context s_GetContext(void)
Get pointer to the thread-specific context.
Definition: ncbi_c_log.c:1277
static int s_SetLogFilesDir(const char *dir, int is_applog)
(Re)Initialize logging file streams.
Definition: ncbi_c_log.c:1610
static char * s_GenerateHitID_Str_Ex(char *dst, int is_api_call, TNcbiLog_UInt8 uid)
Definition: ncbi_c_log.c:1969
static void s_URL_Encode(const void *src_buf, size_t src_size, size_t *src_read, void *dst_buf, size_t dst_size, size_t *dst_written)
URL-encode up to "src_size" symbols(bytes) from buffer "src_buf".
Definition: ncbi_c_log.c:1015
#define VERIFY(expr)
Definition: ncbi_c_log.c:111
#define VERIFY_CATCH(expr)
Definition: ncbi_c_log.c:117
#define MT_INIT
Definition: ncbi_c_log.c:341
static void s_SetState(TNcbiLog_Context ctx, ENcbiLog_AppState state)
Set application state – internal version without MT locking.
Definition: ncbi_c_log.c:2695
void NcbiLogP_ReqStartStr(const char *params)
Variant of NcbiLog_ReqStart, that use already prepared string with parameters.
Definition: ncbi_c_log.c:3574
#define UNKNOWN_SESSION
Definition: ncbi_c_log.c:157
static size_t s_PrintParamsStr(char *dst, size_t pos, const char *params)
Print parameters to message buffer (string version).
Definition: ncbi_c_log.c:2355
void NcbiLogP_ReInit(void)
Definition: ncbi_c_log.c:2638
static size_t s_ReqStart(TNcbiLog_Context ctx)
Definition: ncbi_c_log.c:3446
static void s_SetSession(char *dst, const char *session)
Definition: ncbi_c_log.c:1890
static const char * sx_SeverityStr[]
Definition: ncbi_c_log.c:2375
static void s_Abort(long line, const char *msg)
Definition: ncbi_c_log.c:197
TNcbiLog_Info * NcbiLogP_GetInfoPtr(void)
Definition: ncbi_c_log.c:4020
#define MT_DESTROY
Definition: ncbi_c_log.c:344
static void s_Extra(TNcbiLog_Context ctx, const SNcbiLog_Param *params)
Definition: ncbi_c_log.c:3674
static int s_GetTime(STime *t)
Get current GMT time with nanoseconds (STime version)
Definition: ncbi_c_log.c:795
static volatile int sx_IsEnabled
Definition: ncbi_c_log.c:178
static volatile TNcbiLog_Context sx_ContextST
Definition: ncbi_c_log.c:187
void NcbiLogP_AppStop(int exit_status, int exit_signal, double execution_time)
Should be called immediately prior to the application exit.
Definition: ncbi_c_log.c:3412
static void s_CloseLogFiles(int cleanup)
Close log files for a current destination.
Definition: ncbi_c_log.c:1414
static char * s_StrDup(const char *str)
strdup() doesn't exists on all platforms, and we cannot check this here.
Definition: ncbi_c_log.c:516
#define kIdBufSize
static volatile TNcbiLog_PID sx_PID
Definition: ncbi_c_log.c:190
static void s_TlsSetValue(void *ptr)
Definition: ncbi_c_log.c:443
static void s_InitDestination(const char *logfile_path)
(Re)Initialize destination.
Definition: ncbi_c_log.c:1684
TNcbiLog_UInt8 NcbiLogP_GenerateUID(void)
Generate new unique process ID.
Definition: ncbi_c_log.c:2015
void NcbiLogP_ExtraStr(const char *params)
Variant of NcbiLog_Extra, that use already prepared string with parameters.
Definition: ncbi_c_log.c:3727
static int s_SetLogFiles(const char *path_with_base_name, int is_applog)
(Re)Initialize logging file streams.
Definition: ncbi_c_log.c:1575
static void s_ReportError(long line, const char *msg)
Definition: ncbi_c_log.c:228
#define MT_UNLOCK
Definition: ncbi_c_log.c:343
static char * s_GenerateHitID_Str(char *dst)
Definition: ncbi_c_log.c:2007
#define UNUSED_ARG(x)
Definition: ncbi_c_log.c:136
static TNcbiLog_PID s_GetPID(void)
Get current process ID.
Definition: ncbi_c_log.c:666
static TNcbiLog_Context s_CreateContext(void)
Create thread-specific context.
Definition: ncbi_c_log.c:1234
static size_t s_Write(int fd, const void *buf, size_t count)
Definition: ncbi_c_log.c:2057
static void s_EscapeNewlines(const void *src_buf, size_t src_size, size_t *src_read, void *dst_buf, size_t dst_size, size_t *dst_written)
Escape newlines in the string.
Definition: ncbi_c_log.c:1145
static int s_OpenLogFiles(void)
Open file streams.
Definition: ncbi_c_log.c:1500
#define UNKNOWN_APPNAME
Definition: ncbi_c_log.c:159
#define UNKNOWN_CLIENT
Definition: ncbi_c_log.c:156
const char * NcbiLogP_GetSessionID_Env(void)
This routine is called during start up and again in NcbiLog_ReqStart().
Definition: ncbi_c_log.c:908
static void s_AppStart(TNcbiLog_Context ctx, const char *argv[])
Print "start" message.
Definition: ncbi_c_log.c:3302
#define min_value(a, b)
Definition: ncbi_c_log.c:140
static struct TNcbiLog_MTLock_tag sx_MTLock_Default
Definition: ncbi_c_log.c:317
static const char * s_GetClient_Env(void)
This routine is called during start up and again in NcbiLog_ReqStart().
Definition: ncbi_c_log.c:867
static void s_SetClient(char *dst, const char *client)
Definition: ncbi_c_log.c:1874
void NcbiLogP_PerfStr(int status, double timespan, const char *params)
Variant of NcbiLog_Perf, that use already prepared string with parameters.
Definition: ncbi_c_log.c:3782
static void s_TlsInit(void)
Definition: ncbi_c_log.c:391
static size_t s_PrintParamsPair(char *dst, size_t pos, const char *key, const char *value)
Print one parameter's pair (key, value) to message buffer.
Definition: ncbi_c_log.c:2281
static TNcbiLog_TID s_GetTID(void)
Get current thread ID.
Definition: ncbi_c_log.c:682
static void s_LogHitID(TNcbiLog_Context ctx, const char *hit_id)
Definition: ncbi_c_log.c:3043
int NcbiLogP_GetEnv_UInt(const char *env_var_name, unsigned int *value)
Get value from numeric-based environment variables.
Definition: ncbi_c_log.c:953
void s_SleepMicroSec(unsigned long mc_sec)
Sleep the specified number of microseconds.
Definition: ncbi_c_log.c:494
#define MT_LOCK
Definition: ncbi_c_log.c:342
static const char * kBaseLogDir
Definition: ncbi_c_log.c:166
static void s_Post(TNcbiLog_Context ctx, ENcbiLog_DiagFile diag)
Post prepared message into the log.
Definition: ncbi_c_log.c:2090
static void s_LogSubHitID(TNcbiLog_Context ctx, const char *subhit_id)
Definition: ncbi_c_log.c:3053
#define UNKNOWN_HOST
Definition: ncbi_c_log.c:155
static const char * s_ConcatPath(const char *p1, const char *p2, char *dst, size_t dst_size)
Concatenate two parts of the path (zero-terminated strings) for the current OS.
Definition: ncbi_c_log.c:559
static char * s_GetAppBaseName(const char *path)
Get base name of application.
Definition: ncbi_c_log.c:1189
static void s_DestroyContext(void)
Destroy thread-specific context.
Definition: ncbi_c_log.c:1301
static void s_SetHost(const char *host)
Definition: ncbi_c_log.c:1858
static volatile TNcbiLog_MTLock sx_MTLock
Definition: ncbi_c_log.c:318
void NcbiLogP_Raw2(const char *line, size_t len)
Variant of NcbiLogP_Raw with already known line size to avoid double length calculation.
Definition: ncbi_c_log.c:3868
static volatile int sx_MTLock_Own
Definition: ncbi_c_log.c:323
static size_t s_PrintCommonPrefix(TNcbiLog_Context ctx)
Print common prefix to message buffer.
Definition: ncbi_c_log.c:2172
static size_t s_PrintReqStartExtraParams(size_t pos)
Print extra parameters for request start.
Definition: ncbi_c_log.c:3512
static int s_GetTimeStr(char *buf, time_t time_sec, unsigned long time_ns)
Get current local time in format 'YYYY-MM-DDThh:mm:ss.sss'.
Definition: ncbi_c_log.c:818
#define MT_LOCK_VALID
Definition: ncbi_c_log.c:327
static void s_PrintMessage(ENcbiLog_Severity severity, const char *msg, int print_as_note)
Print a message with severity to message buffer.
Definition: ncbi_c_log.c:2381
#define CATCH
Definition: ncbi_c_log.c:131
static int s_MTLock_Do(ENcbiLog_MTLock_Action action)
Definition: ncbi_c_log.c:330
static int s_AddParamsPair(SNcbiLog_Param params[], int index, const char *key, const char *value)
Add parameters pair to the list if not empty.
Definition: ncbi_c_log.c:2265
static volatile int sx_IsInit
Definition: ncbi_c_log.c:175
static int s_AttachContext(TNcbiLog_Context ctx)
Attach thread-specific context.
Definition: ncbi_c_log.c:1249
static int s_GetTimeT(time_t *time_sec, unsigned long *time_ns)
Update current UID with new timestamp.
Definition: ncbi_c_log.c:760
static char * s_GenerateSID_Str_Ex(char *dst, int use_logging_api, TNcbiLog_UInt8 uid)
Definition: ncbi_c_log.c:1938
#define verify(expr)
Definition: ncbi_c_log.c:97
static void s_SetHitID(char *dst, const char *hit_id)
Definition: ncbi_c_log.c:1905
static size_t s_PrintParams(char *dst, size_t pos, const SNcbiLog_Param *params)
Print parameters to message buffer.
Definition: ncbi_c_log.c:2321
static void s_ExtraStr(TNcbiLog_Context ctx, const char *params)
Definition: ncbi_c_log.c:3695
static volatile int sx_TlsIsInit
Definition: ncbi_c_log.c:381
#define NO_LOG
Logging going not to /log (local file, stderr, etc)
Definition: ncbi_c_log_p.h:98
#define NCBILOG_HITID_MAX
Definition: ncbi_c_log_p.h:64
#define NCBILOG_ENTRY_MIN
Definition: ncbi_c_log_p.h:72
#define NCBILOG_PORT_MAX
Definition: ncbi_c_log_p.h:66
#define NCBILOG_HOST_MAX
Definition: ncbi_c_log_p.h:61
ENcbiLog_DiagFile
Type of file for the output.
Definition: ncbi_c_log_p.h:88
@ eDiag_Perf
.perf
Definition: ncbi_c_log_p.h:92
@ eDiag_Log
.log
Definition: ncbi_c_log_p.h:91
@ eDiag_Err
.err
Definition: ncbi_c_log_p.h:90
#define NCBILOG_ENTRY_MAX
Definition: ncbi_c_log_p.h:76
#define NCBILOG_CLIENT_MAX
Definition: ncbi_c_log_p.h:62
#define CLOSE_FOR_REOPEN
Regular file closure for later reopeng.
Definition: ncbi_c_log_p.h:102
#define NCBILOG_ENTRY_MAX_ALLOC
Maximum length of each log entry, all text after this position will be truncated.
Definition: ncbi_c_log_p.h:75
#define kInvalidFileHandle
Definition: ncbi_c_log_p.h:119
#define CLOSE_CLEANUP
Force logfiles cleanup.
Definition: ncbi_c_log_p.h:101
#define NCBILOG_APPNAME_MAX
Definition: ncbi_c_log_p.h:65
#define TO_LOG
Logging going to /log.
Definition: ncbi_c_log_p.h:97
#define NCBILOG_SESSION_MAX
Definition: ncbi_c_log_p.h:63
EIPRangeType t
Definition: ncbi_localip.c:101
#define STDOUT_FILENO
Definition: ncbicgir.cpp:48
int ssize_t
Definition: ncbiconf_msvc.h:93
#define NCBI_OS_UNIX
int isprint(Uchar c)
Definition: ncbictype.hpp:67
switch(yytype)
Definition: newick.tab.cpp:737
static Format format
Definition: njn_ioutil.cpp:53
void abort()
double f(double x_, const double &y_)
Definition: njn_root.hpp:188
static const char * prefix[]
Definition: pcregrep.c:405
static CNamedPipeClient * client
unsigned int DWORD
Definition: sqltypes.h:98
#define assert(x)
Definition: srv_diag.hpp:58
Application access log and error postings info structure (global).
Definition: ncbi_c_log_p.h:129
unsigned int server_port
$SERVER_PORT on calling/current host
Definition: ncbi_c_log_p.h:172
char * file_trace_name
Saved file names for log files.
Definition: ncbi_c_log_p.h:178
char client[256+1]
App-wide client IP address (UNK_CLIENT if unknown)
Definition: ncbi_c_log_p.h:145
ENcbiLog_Destination destination
Current logging destination.
Definition: ncbi_c_log_p.h:171
TNcbiLog_Counter rid
Request ID (e.g.
Definition: ncbi_c_log_p.h:134
const char * logsite
Pointer to logsite name.
Definition: ncbi_c_log_p.h:188
const char * host_location
Host location (NULL if unknown or not set)
Definition: ncbi_c_log_p.h:159
char * app_base_name
Pointer to application base name.
Definition: ncbi_c_log_p.h:167
const char * host_role
Host role (NULL if unknown or not set)
Definition: ncbi_c_log_p.h:158
TNcbiLog_PID pid
Process ID.
Definition: ncbi_c_log_p.h:133
char * file_log_name
Definition: ncbi_c_log_p.h:180
int remote_logging
1 if logging request is going from remote host
Definition: ncbi_c_log_p.h:163
time_t last_reopen_time
Last reopen time for log files.
Definition: ncbi_c_log_p.h:173
char * file_err_name
Definition: ncbi_c_log_p.h:179
TFileHandle file_perf
Definition: ncbi_c_log_p.h:177
ENcbiLog_AppState state
Application state.
Definition: ncbi_c_log_p.h:135
unsigned int phid_sub_id
App-wide sub-hit ID counter.
Definition: ncbi_c_log_p.h:155
char * message
Buffer used to collect a message and log it.
Definition: ncbi_c_log_p.h:149
ENcbiLog_Severity post_level
Posting level.
Definition: ncbi_c_log_p.h:164
int phid_inherit
1 if PHID set explicitly and should be inherited (by requests)
Definition: ncbi_c_log_p.h:157
char host[256+1]
Name of the host where the process runs (UNK_HOST if unknown)
Definition: ncbi_c_log_p.h:141
char * file_perf_name
Definition: ncbi_c_log_p.h:181
TFileHandle file_err
Definition: ncbi_c_log_p.h:175
int reuse_file_names
File names where not changed, reuse it.
Definition: ncbi_c_log_p.h:182
int split_log_file
Split log files flag.
Definition: ncbi_c_log_p.h:183
int user_posting_time
If 1 use post_time as is, and never change it.
Definition: ncbi_c_log_p.h:140
unsigned int phid_sub_id_limit
Initializes from LOG_ISSUED_SUBHIT_LIMIT env variable.
Definition: ncbi_c_log_p.h:156
int is_applog
1 if logging going to /log
Definition: ncbi_c_log_p.h:184
char appname[3 *1024+1]
Name of the application (UNK_APP if unknown)
Definition: ncbi_c_log_p.h:143
char * app_full_name
Pointer to a full application name (argv[0])
Definition: ncbi_c_log_p.h:166
TNcbiLog_Counter psn
Serial number of the posting within the process.
Definition: ncbi_c_log_p.h:137
TFileHandle file_trace
Saved files for log files.
Definition: ncbi_c_log_p.h:174
char phid[3 *1024+1]
App-wide hit ID (empty string if unknown)
Definition: ncbi_c_log_p.h:153
TFileHandle file_log
Definition: ncbi_c_log_p.h:176
TNcbiLog_UInt8 guid
Globally unique process ID.
Definition: ncbi_c_log_p.h:136
char session[3 *256+1]
App-wide session ID (UNK_SESSION if unknown)
Definition: ncbi_c_log_p.h:147
STime app_start_time
Application start time.
Definition: ncbi_c_log_p.h:165
STime post_time
GMT time at which the message was posted, use current time if it is not specified (equal to 0)
Definition: ncbi_c_log_p.h:138
Thread-specific context data.
Definition: ncbi_c_log_p.h:195
Structure to describe pairs 'key=value', used to posting parameters.
Definition: ncbi_c_log.h:275
Application access log and error postings info structure.
Definition: ncbi_c_log_p.h:107
time_t sec
GMT time.
Definition: ncbi_c_log_p.h:108
unsigned long ns
Nanosecond part of the time.
Definition: ncbi_c_log_p.h:109
unsigned int magic_number
Used internally to make sure it's init'd.
Definition: ncbi_c_log.c:310
FNcbiLog_MTLock_Handler handler
Handler function.
Definition: ncbi_c_log.c:309
void * user_data
For "handler()".
Definition: ncbi_c_log.c:308
#define const
Definition: zconf.h:232
void free(voidpf ptr)
voidp malloc(uInt size)
Modified on Mon May 27 04:36:36 2024 by modify_doxy.py rev. 669887