LCOV - code coverage report
Current view: top level - util/log - fd_log.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 12 21 57.1 %
Date: 2024-11-13 11:58:15 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_util_log_fd_log_h
       2             : #define HEADER_fd_src_util_log_fd_log_h
       3             : 
       4             : /* Note: fd must be booted to use the APIs in this module */
       5             : 
       6             : /* The fd_log conceptually produces up to two log message streams for
       7             :    an application.  One is the ephemeral log message stream (aka
       8             :    "stderr") and the other is permanent log message stream ("the log
       9             :    file").  Messages to "stderr" are abbreviated as somebody watching
      10             :    this stream realtime typically already knows the stream context in
      11             :    great detail (the host, the user, the application, etc).  Messages to
      12             :    the "log file" are much more detailed and thus suitable long time
      13             :    archival purposes.
      14             : 
      15             :    In producing these streams, writes to the log file are prioritized
      16             :    over writes to stderr.  Further, writes to these streams are done
      17             :    quasi-atomically at message granularity to reduce the risk that
      18             :    concurrent log messages from different threads will get mixed
      19             :    together.
      20             : 
      21             :    Default behaviors are:
      22             : 
      23             :    - FD_LOG_DEBUG messages are not written to either stream (the
      24             :      argument list is still processed though so that any side effects of
      25             :      the argument list are not lost).
      26             : 
      27             :    - FD_LOG_INFO messages are written in detailed form to the log file
      28             :      (if the fd_log log file is setup).
      29             : 
      30             :    - FD_LOG_NOTICE is FD_LOG_INFO + messages are written in summary
      31             :      form to stderr.
      32             : 
      33             :    - FD_LOG_WARNING is FD_LOG_NOTICE + the log file and stderr are
      34             :      flushed to minimize the risk of this message and any preceding not
      35             :      making it out before thread resumption.
      36             : 
      37             :    - FD_LOG_ERR is FD_LOG_WARNING + the program will be exited with
      38             :      an error code of 1.
      39             : 
      40             :    - FD_LOG_CRIT and above are FD_LOG_WARNING + the program will
      41             :      do a backtrace if possible to the log file and stderr and, after a
      42             :      brief delay to let any pending fd_log writes complete, aborts the
      43             :      program (which typically also produces a core dump).
      44             : 
      45             :    These log level names mirror the Linux syslog levels.
      46             : 
      47             :    Useful concepts / terms:
      48             : 
      49             :    - An application is a collection of 1 or more thread groups that have
      50             :      common log.
      51             : 
      52             :    - A thread group is a collection of 1 or more threads.  (It typically
      53             :      is a process but there are unhosted situations when a more
      54             :      generalized notion of process is required.)
      55             : 
      56             :    - The log has a single wall clock for timestamping log messages.
      57             : 
      58             :    - Log messages timestamps reflect the time when log message creation
      59             :      starts.
      60             : 
      61             :    - Back-to-back reads of the wallclock by a thread should be
      62             :      monotonically increasing such that the order in which that thread's
      63             :      log messages were generated is accurately reflected by the
      64             :      timestamps.
      65             : 
      66             :    - Concurrent reads of the wallclock by different threads should be
      67             :      reasonably well synchronized such that ordering of events between
      68             :      communicating threads is accurately reflected by the timestamps.
      69             : 
      70             :    - A thread runs on a cpu.
      71             : 
      72             :    - A CPU has an architecture (x86 cores, ASIC cores, FPGAs, GPU MPUs,
      73             :      etc).
      74             : 
      75             :    - Multiple CPU architectures might be used by an application.
      76             : 
      77             :    - A host is a collection of cpus for which shared memory style
      78             :      communication primitives are reasonably efficient.
      79             : 
      80             :    - CPUs in a host need not share a common memory address space.
      81             : 
      82             :    - CPUs in a host need not share a common architecture.
      83             : 
      84             :    - Threads in a thread group run on the same host.
      85             : 
      86             :    - Threads in a thread group run on the same architecture.
      87             : 
      88             :    - Threads in a thread group share a common address space.
      89             : 
      90             :    - Threads in a thread group share a common group global variables.
      91             : 
      92             :    - A thread group will be part of one application for its lifetime.
      93             : 
      94             :    - A thread will be part of only one thread group for its lifetime.
      95             : 
      96             :    - A thread will run on only one host for its lifetime.
      97             : 
      98             :    - A thread will run on only one architecture for its lifetime.
      99             : 
     100             :    - An application thread's thread id is unique over all running
     101             :      threads in an application.
     102             : 
     103             :    - An application thread's thread id reasonably cheaply identifies the
     104             :      thread group to which the thread belongs.
     105             : 
     106             :    - Typically, the set of threads in a thread group will be constant
     107             :      for the lifetime of the thread group (but this is not strictly
     108             :      required).
     109             : 
     110             :    - Typically, the set of threads groups in an application will be
     111             :      constant for the lifetime of the application (but this is not
     112             :      strictly required).
     113             : 
     114             :    - Typically, a thread will run on only one CPU for its lifetime
     115             :      (but this is not strictly required).
     116             : 
     117             :    - Typically, a CPU will only be responsible for the execution of at
     118             :      most one application thread at any given time (but this is not
     119             :      strictly required).
     120             : 
     121             :    The above implies:
     122             : 
     123             :    * The synchronization of concurrent clock reads between two
     124             :      communicating application threads should be tighter than the
     125             :      latency for these two threads to communicate (e.g. T_send < T_recv
     126             :      is preserved).
     127             : 
     128             :    * The range over which the this can be done (i.e. the range of which
     129             :      the wallclock can be distributed with good synchronization and
     130             :      reasonably cheaply read) is the range over which application
     131             :      threads can be distributed.
     132             : 
     133             :    * There exist efficient forms of address space translation /
     134             :      virtualization to facilitate shared memory style communication
     135             :      between application threads on a host.
     136             : 
     137             :    * Communications between threads on different hosts is done via
     138             :      message passing.
     139             : 
     140             :    * Communications between threads on the same host can be done either
     141             :      by message passing or via shared memory. */
     142             : 
     143             : #include "../env/fd_env.h"
     144             : #include "../io/fd_io.h"
     145             : 
     146             : /* FD_LOG_NOTICE(( ... printf style arguments ... )) will send a message
     147             :    at the NOTICE level to the logger.  E.g. for a typical fd_log
     148             :    configuration:
     149             : 
     150             :      FD_LOG_NOTICE(( "%lu is the loneliest number", 1UL ));
     151             : 
     152             :    would log something like:
     153             : 
     154             :      NOTICE  01-23 04:56:07.890123 45678 f0 0 src/file.c(901): 1 is the loneliest number
     155             : 
     156             :    to the ephemeral log (stderr) and log something like:
     157             : 
     158             :      NOTICE  2023-01-23 04:56:07.890123456 GMT-06 45678:45678 user:host:f0 app:thread:0 src/file.c(901)[func]: 1 is the loneliest number
     159             : 
     160             :    to the permanent log (log file).  Similarly for the other log levels.
     161             :    Additional logger details are described at the top of this file.
     162             : 
     163             :    FD_LOG_NOTICE has a hexdump counterpart that essentially behaves
     164             :    like:
     165             : 
     166             :      void
     167             :      FD_LOG_HEXDUMP_NOTICE(( char const * tag,
     168             :                              void const * mem,
     169             :                              ulong        sz ));
     170             : 
     171             :    This logs pretty printed details about memory region to the log
     172             :    streams at the NOTICE log severity level.
     173             : 
     174             :    tag points to a cstr that is intended to be a human-readable /
     175             :    greppable tag describing the memory region.  As such, it is strongly
     176             :    recommended that tag points to a cstr containing only printable
     177             :    characters with no internal double quotes (but this is not enforced
     178             :    currently).  There are no length restrictions on the cstr but the
     179             :    logger under the hood might detectably truncate excessively long tags
     180             :    (e.g. strlen(tag) >> 32) due to internal implementation limitations.
     181             :    NULL and/or empty tags ("") are fine and will be detectably logged.
     182             : 
     183             :    mem points to the first byte of the memory region to hexdump and sz
     184             :    is the number of bytes in the region.  There are no limits on sz but
     185             :    the number of bytes logged might be limited due to internal
     186             :    implementation details (e.g. sz >> 1500 bytes).  NULL mem and/or 0 sz
     187             :    are fine and will be detectably logged.
     188             : 
     189             :    The lifetime the cstr and the memory region must be at least from the
     190             :    call entry to call return.
     191             : 
     192             :    E.g. for a typical fd_log configuration:
     193             : 
     194             :      FD_LOG_HEXDUMP_WARNING(( "bad_pkt", pkt, pkt_sz ));
     195             : 
     196             :    would log something like:
     197             : 
     198             :      WARNING 01-23 04:56:07.890123 75779 f0 0 src/file.c(901): HEXDUMP "bad_pkt" (96 bytes at 0x555555561a4e)
     199             :              0000:  30 31 32 33 34 35 36 37 38 39 41 42 43 44 45 46  0123456789ABCDEF
     200             :              0010:  47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56  GHIJKLMNOPQRSTUV
     201             :              0020:  57 58 59 5a 61 62 63 64 65 66 67 68 69 6a 6b 6c  WXYZabcdefghijkl
     202             :              0030:  6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a 20 7e  mnopqrstuvwxyz ~
     203             :              0040:  21 40 23 24 25 5e 26 2a 28 29 5f 2b 60 2d 3d 5b  !@#$%^&*()_+`-=[
     204             :              0050:  5d 5c 3b 27 2c 2e 2f 7b 7d 7c 3a 22 3c 3e 3f 00  ]\;',./{}|:"<>?.
     205             : 
     206             :    to the ephemeral log (stderr) and similarly to the permanent log.
     207             : 
     208             :    Similarly for hexdumping to other log levels.
     209             : 
     210             :    Note: fd_log_wallclock called outside the arg list to give it a
     211             :    linguistically strict point when it is called that is before logging
     212             :    activities commence.
     213             : 
     214             :    This family of functions is not async-signal safe. Do not call log functions from
     215             :    a signal handler, it may deadlock or corrupt the log. If you wish to write
     216             :    emergency diagnostics, you can call `write(2)` directly to stderr or the log file,
     217             :    which is safe. */
     218             : 
     219      705960 : #define FD_LOG_DEBUG(a)           do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_1( 0, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_0           a ); } while(0)
     220    19760904 : #define FD_LOG_INFO(a)            do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_1( 1, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_0           a ); } while(0)
     221       68843 : #define FD_LOG_NOTICE(a)          do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_1( 2, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_0           a ); } while(0)
     222     1000497 : #define FD_LOG_WARNING(a)         do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_1( 3, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_0           a ); } while(0)
     223     3145728 : #define FD_LOG_ERR(a)             do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_2( 4, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_0           a ); } while(0)
     224           0 : #define FD_LOG_CRIT(a)            do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_2( 5, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_0           a ); } while(0)
     225           0 : #define FD_LOG_ALERT(a)           do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_2( 6, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_0           a ); } while(0)
     226           0 : #define FD_LOG_EMERG(a)           do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_2( 7, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_0           a ); } while(0)
     227             : 
     228        6192 : #define FD_LOG_HEXDUMP_DEBUG(a)   do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_1( 0, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_hexdump_msg a ); } while(0)
     229          69 : #define FD_LOG_HEXDUMP_INFO(a)    do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_1( 1, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_hexdump_msg a ); } while(0)
     230           3 : #define FD_LOG_HEXDUMP_NOTICE(a)  do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_1( 2, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_hexdump_msg a ); } while(0)
     231          72 : #define FD_LOG_HEXDUMP_WARNING(a) do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_1( 3, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_hexdump_msg a ); } while(0)
     232             : #define FD_LOG_HEXDUMP_ERR(a)     do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_2( 4, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_hexdump_msg a ); } while(0)
     233             : #define FD_LOG_HEXDUMP_CRIT(a)    do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_2( 5, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_hexdump_msg a ); } while(0)
     234             : #define FD_LOG_HEXDUMP_ALERT(a)   do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_2( 6, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_hexdump_msg a ); } while(0)
     235             : #define FD_LOG_HEXDUMP_EMERG(a)   do { long _fd_log_msg_now = fd_log_wallclock(); fd_log_private_2( 7, _fd_log_msg_now, __FILE__, __LINE__, __func__, fd_log_private_hexdump_msg a ); } while(0)
     236             : 
     237             : /* FD_LOG_STDOUT(()) is used for writing formatted messages to STDOUT, it does not
     238             :    take a lock and might interleave with other messages to the same pipe.  It
     239             :    should only be used for command output. */
     240           0 : #define FD_LOG_STDOUT(a) do { fd_log_private_fprintf_nolock_0( STDOUT_FILENO, "%s", fd_log_private_0 a ); } while(0)
     241             : 
     242             : /* FD_TEST is a single statement that evaluates condition c and, if c
     243             :    evaluates to false, will FD_LOG_ERR that the condition failed.  It is
     244             :    optimized for the case where c will is non-zero.  This is mostly
     245             :    meant for use in things like unit tests.  Due to linguistic
     246             :    limitations, c cannot contain things like double quotes, etc.  E.g.
     247             : 
     248             :      FD_TEST( broken_func_that_should_return_zero( arg1, arg2 )!=0 );
     249             : 
     250             :    would typically cause the program to exit with error code 1, logging
     251             :    something like:
     252             : 
     253             :      ERR     01-23 04:56:07.890123 45678 f0 0 src/foo.c(901): FAIL: broken_func_that_should_return_zero( arg1, arg2 )!=0
     254             : 
     255             :    to the ephemeral log (stderr) and something like:
     256             : 
     257             :      ERR     2023-01-23 04:56:07.890123456 GMT-06 45678:45678 user:host:f0 app:thread:0 src/foo.c(901)[func]: FAIL: broken_func_that_should_return_zero( arg1, arg2 )!=0
     258             : 
     259             :    to the permanent log.  And similarly for other log levels.
     260             : 
     261             :    This macro is robust. */
     262             : 
     263 >20858*10^7 : #define FD_TEST(c) do { if( FD_UNLIKELY( !(c) ) ) FD_LOG_ERR(( "FAIL: %s", #c )); } while(0)
     264             : 
     265             : /* FD_TEST_CUSTOM is like FD_TEST but with a custom error msg err. */
     266             : 
     267      110031 : #define FD_TEST_CUSTOM(c,err) do { if( FD_UNLIKELY( !(c) ) ) FD_LOG_ERR(( "FAIL: %s", (err) )); } while(0)
     268             : 
     269             : /* Macros for doing hexedit / tcpdump-like logging of memory regions.
     270             :    E.g.
     271             : 
     272             :      FD_LOG_NOTICE(( "cache line %016lx\n\t"
     273             :                      "%02x: " FD_LOG_HEX16_FMT "\n\t"
     274             :                      "%02x: " FD_LOG_HEX16_FMT "\n\t"
     275             :                      "%02x: " FD_LOG_HEX16_FMT "\n\t"
     276             :                      "%02x: " FD_LOG_HEX16_FMT,
     277             :                      (ulong)mem,
     278             :                       0U, FD_LOG_HEX16_FMT_ARGS( mem    ),
     279             :                      16U, FD_LOG_HEX16_FMT_ARGS( mem+16 ),
     280             :                      32U, FD_LOG_HEX16_FMT_ARGS( mem+32 ),
     281             :                      48U, FD_LOG_HEX16_FMT_ARGS( mem+48 ) ));
     282             : 
     283             :    would log something like:
     284             : 
     285             :      NOTICE  01-23 04:56:07.890123 45678 f0 0 src/foo.c(901): cache line 0123456789abcd00
     286             :              00: 00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f
     287             :              10: 10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f
     288             :              20: 20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f
     289             :              30: 30 31 32 33 34 35 36 37  38 39 3a 3b 3c 3d 3e 3f
     290             : 
     291             :    to the ephemeral log typically (and a more detailed message to the
     292             :    permanent log).  And similarly for the other log levels.  b should be
     293             :    safe against multiple evaluation. */
     294             : 
     295             : #define FD_LOG_HEX16_FMT "%02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x"
     296             : #define FD_LOG_HEX16_FMT_ARGS(b)                                      \
     297             :   (uint)(((uchar const *)(b))[ 0]), (uint)(((uchar const *)(b))[ 1]), \
     298             :   (uint)(((uchar const *)(b))[ 2]), (uint)(((uchar const *)(b))[ 3]), \
     299             :   (uint)(((uchar const *)(b))[ 4]), (uint)(((uchar const *)(b))[ 5]), \
     300             :   (uint)(((uchar const *)(b))[ 6]), (uint)(((uchar const *)(b))[ 7]), \
     301             :   (uint)(((uchar const *)(b))[ 8]), (uint)(((uchar const *)(b))[ 9]), \
     302             :   (uint)(((uchar const *)(b))[10]), (uint)(((uchar const *)(b))[11]), \
     303             :   (uint)(((uchar const *)(b))[12]), (uint)(((uchar const *)(b))[13]), \
     304             :   (uint)(((uchar const *)(b))[14]), (uint)(((uchar const *)(b))[15])
     305             : 
     306             : #define FD_LOG_HEX20_FMT "%02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
     307             : #define FD_LOG_HEX20_FMT_ARGS(b)                                      \
     308             :   FD_LOG_HEX16_FMT_ARGS(b),                                           \
     309             :   (uint)(((uchar const *)(b))[16]), (uint)(((uchar const *)(b))[17]), \
     310             :   (uint)(((uchar const *)(b))[18]), (uint)(((uchar const *)(b))[19])
     311             : 
     312      340182 : #define FD_LOG_NAME_MAX (40UL)
     313             : 
     314             : FD_PROTOTYPES_BEGIN
     315             : 
     316             : /* APPLICATION LOGICAL IDENTIFIERS ************************************/
     317             : 
     318             : /* fd_log_app_id() returns an integer application id of the application
     319             :    to which the caller belongs.  An application id is intended, at a
     320             :    minimum, to uniquely identify all concurrently running applications
     321             :    in the enterprise.  This is cheap after the first call. */
     322             : 
     323             : FD_FN_PURE ulong fd_log_app_id( void );
     324             : 
     325             : /* fd_log_app() returns a non-NULL pointer to a cstr describing the
     326             :    application to which the caller belongs.  This is typically something
     327             :    provided to the caller when the caller started.  This is cheap after
     328             :    the first call and the lifetime of the returned string is infinite
     329             :    from the caller's point of view.  strlen(fd_log_app()) is in
     330             :    [1,FD_LOG_NAME_MAX). */
     331             : 
     332             : FD_FN_CONST char const * fd_log_app( void ); /* Pointer is CONST, cstr pointed at is PURE */
     333             : 
     334             : /* fd_log_thread_id() returns the caller's integer thread id.  A thread
     335             :    id is intended, at a minimum, to be unique over all concurrently
     336             :    running threads in the application.  This is cheap after the first
     337             :    call. */
     338             : 
     339             : ulong fd_log_thread_id( void );
     340             : 
     341             : /* fd_log_thread() returns a non-NULL pointer to a cstr describing the
     342             :    caller.  This defaults to some target specific default essentially
     343             :    determined at the caller's startup and can be explicitly set by the
     344             :    caller.  This is cheap after the first call within a thread and the
     345             :    lifetime of the returned pointer is until the next time the name is
     346             :    set or the caller terminates.  strlen(fd_log_thread()) is in
     347             :    [1,FD_LOG_NAME_MAX). */
     348             : 
     349             : char const * fd_log_thread( void );
     350             : 
     351             : /* fd_log_thread_set() sets the caller's description to the cstr
     352             :    pointed to by name.  A NULL name and/or an empty name ("") indicate
     353             :    to reset to the description that would have been assigned if the
     354             :    caller started at the time this is called.  name is not changed by
     355             :    the function and the fd_log does not retain any interest in name
     356             :    after return.  The actual resulting description will be truncated to
     357             :    a strlen of FD_LOG_NAME_MAX-1 if name is longer and potentially
     358             :    sanitized in other ways as necessary for the log. */
     359             : 
     360             : void
     361             : fd_log_thread_set( char const * name );
     362             : 
     363             : /* APPLICATION PHYSICAL IDENTIFIERS ***********************************/
     364             : 
     365             : /* fd_log_host_id() returns an integer host id of the host on which the
     366             :    caller is running.  A host id is intended, at a minimum, to uniquely
     367             :    identify a host enterprise wide.  This cheap after the first call. */
     368             : 
     369             : FD_FN_PURE ulong fd_log_host_id( void );
     370             : 
     371             : /* fd_log_host() returns a non-NULL pointer to a cstr describing the
     372             :    host on which the caller is running.  In simple cases, this defaults
     373             :    to the hostname.  In general cases, this is something provided to the
     374             :    caller at that caller's startup.  This is cheap after the first call
     375             :    and the lifetime of the returned string is infinite from the caller's
     376             :    point of view.  strlen(fd_log_host()) is in [1,FD_LOG_NAME_MAX). */
     377             : 
     378             : FD_FN_CONST char const * fd_log_host( void ); /* ptr is CONST, cstr pointed at is PURE */
     379             : 
     380             : /* fd_log_cpu_id() returns an integer cpu id of one of the cpus on
     381             :    where the caller was allowed to run when first called by a thread (or
     382             :    boot if the caller is the one that booted fd).  A cpu id is intended
     383             :    to uniquely identify a cpu on a host (e.g. for a host with
     384             :    homogeneous x86 cores, idx from /proc/cpuinfo).  This is cheap after
     385             :    the first call. */
     386             : 
     387             : ulong fd_log_cpu_id( void );
     388             : 
     389             : /* fd_log_cpu() returns a non-NULL pointer to a cstr describing the cpu
     390             :    on which the caller is running.  This defaults to some target
     391             :    specific default determined when first called on a thread (or boot if
     392             :    the caller is the one that booted fd).  This is cheap after the first
     393             :    call by a thread and the returned string is infinite from the
     394             :    caller's point of view.  strlen(fd_log_cpu()) is in
     395             :    [1,FD_LOG_NAME_MAX). */
     396             : 
     397             : char const * fd_log_cpu( void );
     398             : 
     399             : /* fd_log_cpu_set() sets the description of the cpu on which the caller
     400             :    is running on to the cstr pointed to by name.  A NULL name and/or an
     401             :    empty name ("") indicate to reset to the description that would have
     402             :    been assigned if the caller started at the time this is called.  name
     403             :    is not changed by the function and the fd_log does not retain any
     404             :    interest in name after return.  The actual resulting description will
     405             :    be truncated to a strlen of FD_LOG_NAME_MAX-1 if name is longer and
     406             :    potentially sanitized in other ways as necessary for the log. */
     407             : 
     408             : void
     409             : fd_log_cpu_set( char const * name );
     410             : 
     411             : /* THREAD GROUP RELATED IDENTIFIERS ***********************************/
     412             : 
     413             : /* fd_log_group_id() returns the thread group id of the thread group to
     414             :    which the caller belongs.  The thread group id is intended, at a
     415             :    minimum, to be unique over all thread groups on a host.  In simple
     416             :    cases, this is the OS pid of the process to which the caller belongs.
     417             :    In general cases, this is typically something provided to the caller
     418             :    when the caller started.  This is cheap after the first call.
     419             : 
     420             :    For sanity, this should be at least 2 (e.g. in POSIX group_id is
     421             :    equivalent to pid and pids<=1 are special such that a user is highly
     422             :    likely to assume group ids <= 1 are special). */
     423             : 
     424             : FD_FN_PURE ulong fd_log_group_id( void );
     425             : 
     426             : /* fd_log_group() returns a non-NULL pointer to a cstr describing the
     427             :    thread group to which the caller belongs.  In simple cases, this
     428             :    defaults to an abbreviated version of argv[0].  In general cases,
     429             :    this is typically something provided to the caller when the caller
     430             :    started.  This is cheap after the first call and the lifetime of the
     431             :    returned string is infinite from the caller's point of view.  The
     432             :    actual pointer and cstr is the same for all threads in the group. */
     433             : 
     434             : FD_FN_CONST char const * fd_log_group( void ); /* ptr is CONST, cstr pointed at is PURE */
     435             : 
     436             : /* fd_log_tid() returns the caller's thread group thread id.  A thread
     437             :    group thread id is intended, at a minimum, to be unique over all
     438             :    running threads in a thread group.  In simple cases, this is the
     439             :    caller's OS tid.  In general cases, this is typically something
     440             :    provided to the thread when that thread started.  This is cheap after
     441             :    the first call. */
     442             : 
     443             : ulong fd_log_tid( void );
     444             : 
     445             : /* fd_log_user_id() returns the user id of the thread group to which the
     446             :    caller belongs.  The user id is intended, at a minimum, to be unique
     447             :    over all users on a host.  In simple cases, this is the OS uid of the
     448             :    process to which the caller belongs.  In general cases, this is
     449             :    typically something provided to the caller when the caller started.
     450             :    This is cheap after the first call. */
     451             : 
     452             : FD_FN_PURE ulong fd_log_user_id( void );
     453             : 
     454             : /* fd_log_user() returns a non-NULL pointer to a cstr describing the
     455             :    user that created the thread group to which the caller belongs.  In
     456             :    simple cases, this defaults to the LOGNAME / login that started the
     457             :    process running the caller.  In general cases, this is something
     458             :    provided to the caller at that caller's startup.  This is cheap after
     459             :    the first call and the lifetime of the returned string is infinite
     460             :    from the caller's point of view.  strlen(fd_log_user()) is in
     461             :    [1,FD_LOG_NAME_MAX). */
     462             : 
     463             : FD_FN_CONST char const * fd_log_user( void ); /* ptr is CONST, cstr pointed at is PURE */
     464             : 
     465             : /* fd_log_group_id_query() returns the status of group_id.  Will be a
     466             :    FD_LOG_GROUP_ID_QUERY_* code.  Positive indicates live, zero
     467             :    indicates dead, negative indicates failure reason. */
     468             : 
     469           0 : #define FD_LOG_GROUP_ID_QUERY_LIVE  (1)  /* group_id is live */
     470           0 : #define FD_LOG_GROUP_ID_QUERY_DEAD  (0)  /* group_id is not live */
     471           0 : #define FD_LOG_GROUP_ID_QUERY_INVAL (-1) /* query failed because invalid group_id (e.g. group_id does to map to a host pid) */
     472           0 : #define FD_LOG_GROUP_ID_QUERY_PERM  (-2) /* query failed because caller lacks permissions */
     473           0 : #define FD_LOG_GROUP_ID_QUERY_FAIL  (-3) /* query failed for unknown reason (should not happen) */
     474             : 
     475             : int fd_log_group_id_query( ulong group_id );
     476             : 
     477             : /* FIXME: TID DESC? */
     478             : 
     479             : /* Build info APIs ****************************************************/
     480             : 
     481             : /* fd_log_build_info points in the caller's address space to the first
     482             :    byte of a memory region of size fd_log_build_info_sz containing a
     483             :    cstr with information about the environment in which the calling code
     484             :    was built.
     485             : 
     486             :    If build information was not available at compile time, the build
     487             :    info will be the empty string and size will be one.
     488             : 
     489             :    The value in this field is the last time the build info file was
     490             :    generated (such that, in a development compile-execute-debug
     491             :    iteration, the build info reflect the build environment since the
     492             :    last "make clean" or the developer manually deleted the build info).
     493             : 
     494             :    Code that is meant to be general purpose should not assume any
     495             :    particular format, contents, length, etc.  The build system,
     496             :    packaging manager, distribution manager, etc might external impose
     497             :    additional requirements on this string for application specific code
     498             :    though. */
     499             : 
     500             : extern char const  fd_log_build_info[] __attribute__((aligned(1)));
     501             : extern ulong const fd_log_build_info_sz; /* == strlen( fd_log_build_info ) + 1UL */
     502             : 
     503             : /* Logging helper APIs ************************************************/
     504             : 
     505             : /* fd_log_wallclock() reads the host's wallclock as ns since the UNIX
     506             :    epoch GMT.  On x86, this uses clock_gettime/CLOCK_REALTIME under the
     507             :    hood and is reasonably cheap (~25-50 ns nowadays).  But it still may
     508             :    involve system calls under the hood and is much slower than, say,
     509             :    RTSDC. */
     510             : 
     511             : long fd_log_wallclock( void );
     512             : 
     513             : /* fd_log_wallclock_cstr( t, buf ) pretty prints the wallclock
     514             :    measurement t as:
     515             :      "YYYY-MM-DD hh:mm:ss.nnnnnnnnn GMT+TZ".
     516             :    or in cases where conversion is not locally practical:
     517             :      "         ssssssssss.nnnnnnnnn s UNIX"
     518             :    buf must be a character buffer of at least
     519             :    FD_LOG_WALLCLOCK_CSTR_BUF_SZ bytes.  Returns buf and buf will be
     520             :    populated with the desired cstr on return. */
     521             : 
     522             : #define FD_LOG_WALLCLOCK_CSTR_BUF_SZ (37UL)
     523             : 
     524             : char *
     525             : fd_log_wallclock_cstr( long   t,
     526             :                        char * buf );
     527             : 
     528             : /* fd_log_sleep puts the calling thread to sleep for dt ns.  dt<=0 is
     529             :    assumed to be a sched_yield request.  Returns the amount of sleep
     530             :    remaining if the sleep was interrupted. */
     531             : 
     532             : long
     533             : fd_log_sleep( long dt );
     534             : 
     535             : /* fd_log_wait_until waits until fd_log_wallclock() is at least then.
     536             :    Returns the time on the clock when the wait ended (will be at least
     537             :    then).  This makes a best effort to be a good citizen and sleep /
     538             :    yield / hyperthreading friendly the caller while also being as
     539             :    precise on the wait as possible (i.e. limited by the overhead
     540             :    fd_log_wallclock).  That is, as the time remaining to wait decreases,
     541             :    the wait gets progressively more precise and CPU intensive.  If
     542             :    remaining is the number of ns remaining in the wait, then:
     543             : 
     544             :                remaining <~   1 us: spin
     545             :        1 us <~ remaining <~ 100 ms: hyper threading friendly spin
     546             :      100 ms <~ remaining <~   1  s: yielding spin
     547             :        1  s <~ remaining          : sleep until ~100 ms remaining
     548             : 
     549             :    If (as is usually the case) fd_log_sleep precision is much better
     550             :    than <<~100 ms accurate, FD_YIELD() delays take <<~100ms and
     551             :    FD_SPIN_PAUSE() << 1 us, the return value will be an accurate read of
     552             :    the fd_log_wallclock at the time of return and within the overhead of
     553             :    fd_log_wallclock. */
     554             : 
     555             : long
     556             : fd_log_wait_until( long then );
     557             : 
     558             : /* fd_log_flush() manually flushes the log (e.g. log a bunch of low
     559             :    priority messages and then flush to ensure the bunch gets written out
     560             :    before proceeding). */
     561             : 
     562             : void
     563             : fd_log_flush( void );
     564             : 
     565             : /* These all the logging levels to be configured at runtime.  These do
     566             :    no validation of there inputs so the values may not behave like the
     567             :    caller things (e.g. stderr<logfile will be treated as
     568             :    stderr==logfile, flush<stderr will be treated as flush==stderr,
     569             :    core<4 will be treated as 4).  colorize returns the colorization mode
     570             :    of the ephemeral log.  Currently, zero indicates no colorization of
     571             :    the ephemeral log and non-zero indicates to colorize it. */
     572             : 
     573             : int fd_log_colorize( void );
     574             : int fd_log_level_logfile ( void );
     575             : int fd_log_level_stderr  ( void );
     576             : int fd_log_level_flush   ( void );
     577             : int fd_log_level_core    ( void );
     578             : 
     579             : void fd_log_colorize_set     ( int mode  );
     580             : void fd_log_level_logfile_set( int level );
     581             : void fd_log_level_stderr_set ( int level );
     582             : void fd_log_level_flush_set  ( int level );
     583             : void fd_log_level_core_set   ( int level );
     584             : 
     585             : /* These functions are for fd_log internal use only. */
     586             : 
     587             : void
     588             : fd_log_private_fprintf_0( int fd, char const * fmt, ... ) __attribute__((format(printf,2,3))); /* Type check the fmt string at compile time */
     589             : 
     590             : void
     591             : fd_log_private_fprintf_nolock_0( int fd, char const * fmt, ... ) __attribute__((format(printf,2,3))); /* Type check the fmt string at compile time */
     592             : 
     593             : char const *
     594             : fd_log_private_0( char const * fmt, ... ) __attribute__((format(printf,1,2))); /* Type check the fmt string at compile time */
     595             : 
     596             : void
     597             : fd_log_private_1( int          level,
     598             :                   long         now,
     599             :                   char const * file,
     600             :                   int          line,
     601             :                   char const * func,
     602             :                   char const * msg );
     603             : 
     604             : void
     605             : fd_log_private_2( int          level,
     606             :                   long         now,
     607             :                   char const * file,
     608             :                   int          line,
     609             :                   char const * func,
     610             :                   char const * msg ) __attribute__((noreturn)); /* Let compiler know this will not be returning */
     611             : 
     612             : void
     613             : fd_log_private_raw_2( char const * file,
     614             :                       int          line,
     615             :                       char const * func,
     616             :                       char const * msg ) __attribute__((noreturn)); /* Let compiler know this will not be returning */
     617             : 
     618             : char const *
     619             : fd_log_private_hexdump_msg( char const * tag,
     620             :                             void const * mem,
     621             :                             ulong        sz );
     622             : 
     623             : void
     624             : fd_log_private_boot( int *    pargc,
     625             :                      char *** pargv );
     626             : 
     627             : void
     628             : fd_log_private_boot_custom( int *        lock,
     629             :                             ulong        app_id,
     630             :                             char const * app,
     631             :                             ulong        thread_id,
     632             :                             char const * thread,
     633             :                             ulong        host_id,
     634             :                             char const * host,
     635             :                             ulong        cpu_id,
     636             :                             char const * cpu,
     637             :                             ulong        group_id,
     638             :                             char const * group,
     639             :                             ulong        tid,
     640             :                             ulong        user_id,
     641             :                             char const * user,
     642             :                             int          dedup,
     643             :                             int          colorize,
     644             :                             int          level_logfile,
     645             :                             int          level_stderr,
     646             :                             int          level_flush,
     647             :                             int          level_core,
     648             :                             int          log_fd,
     649             :                             char const * log_path );
     650             : 
     651             : 
     652             : void
     653             : fd_log_private_halt( void );
     654             : 
     655             : ulong fd_log_private_main_stack_sz( void ); /* Returns ulimit -s (if reasonable) on success, 0 on failure (logs details) */
     656             : 
     657             : ulong
     658             : fd_log_private_tid_default( void );
     659             : 
     660             : ulong
     661             : fd_log_private_cpu_id_default( void );
     662             : 
     663             : void
     664             : fd_log_private_stack_discover( ulong   stack_sz,  /* Size the stack is expected to be */
     665             :                                ulong * _stack0,   /* [*_stack0,*_stack1) is the caller's stack region (will have stack_sz */
     666             :                                ulong * _stack1 ); /* bytes) on success.  Both set to 0UL on failure (logs details). */
     667             : 
     668             : /* These are exposed to allow the user to override the values set at
     669             :    boot/halt time.  If these are used, they are usually a sign of
     670             :    working around a higher level architectural or operational issue. */
     671             : 
     672             : void fd_log_private_app_id_set   ( ulong app_id    );
     673             : void fd_log_private_thread_id_set( ulong thread_id );
     674             : void fd_log_private_host_id_set  ( ulong host_id   );
     675             : void fd_log_private_cpu_id_set   ( ulong cpu_id    );
     676             : void fd_log_private_group_id_set ( ulong group_id  );
     677             : void fd_log_private_tid_set      ( ulong tid       );
     678             : void fd_log_private_user_id_set  ( ulong user_id   );
     679             : 
     680             : void fd_log_private_app_set  ( char const * app   ); /* Not thread safe */
     681             : void fd_log_private_host_set ( char const * host  ); /* Not thread safe */
     682             : void fd_log_private_group_set( char const * group ); /* Not thread safe */
     683             : void fd_log_private_user_set ( char const * user  ); /* Not thread safe */
     684             : 
     685             : /* This is exposed to allow the user to know the expected file descriptor
     686             :    for filtering and security, it should never be used to actually write
     687             :    logs and that should be done by the functions in fd_log.h */
     688             : int fd_log_private_logfile_fd( void );
     689             : 
     690             : FD_PROTOTYPES_END
     691             : 
     692             : #endif /* HEADER_fd_src_util_log_fd_log_h */

Generated by: LCOV version 1.14