LCOV - code coverage report
Current view: top level - util/log - fd_log.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 14 25 56.0 %
Date: 2025-11-28 04:36:48 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 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      138990 : #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           5 : #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       48298 : #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     1092621 : #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     3146859 : #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        6210 : #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         177 : #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      141321 : #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           0 : #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           0 : #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 >35820*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        6915 : #define FD_TEST_CUSTOM(c,err) do { if( FD_UNLIKELY( !(c) ) ) FD_LOG_ERR(( "FAIL: %s", (err) )); } while(0)
     268             : 
     269             : /* FD_PARANOID / FD_CRIT / FD_ALERT:
     270             : 
     271             :    FD_PARANOID configures the FD_CRIT / FD_ALERT runtime checks.
     272             : 
     273             :    If FD_PARANOID is set: FD_CRIT / FD_ALERT will FD_LOG_CRIT /
     274             :    FD_LOG_ALERT the application if c evaluates to false with a
     275             :    descriptive error that includes the user message m (m should evaluate
     276             :    to a cstr when c is false).
     277             : 
     278             :    If not set: FD_CRIT will evaluate c (such that any side effects of c
     279             :    will still happen), the false code path will be marked as unreachable
     280             :    (such that the optimizer will treat the code following the FD_CRIT
     281             :    the same as when paranoid was set) and m will not be evaluated.
     282             :    FD_ALERT will not evaluate c or m.
     283             : 
     284             :    In short, use FD_ALERT when c is expensive to evalute but has no side
     285             :    effects.  Use FD_CRIT for all other cases.
     286             : 
     287             :    FIXME: probably should rename FD_TEST_CUSTOM to FD_ERR. */
     288             : 
     289             : #ifndef FD_PARANOID
     290             : #define FD_PARANOID 0
     291             : #endif
     292             : 
     293             : #if FD_PARANOID
     294             : #define FD_CRIT( c,m) do { if( FD_UNLIKELY( !(c) ) ) FD_LOG_CRIT (( "FAIL: %s (%s)", #c, (m) )); } while(0)
     295             : #define FD_ALERT(c,m) do { if( FD_UNLIKELY( !(c) ) ) FD_LOG_ALERT(( "FAIL: %s (%s)", #c, (m) )); } while(0)
     296             : #else
     297   204143217 : #define FD_CRIT( c,m) do { (void)(c); } while(0)
     298    12889212 : #define FD_ALERT(c,m) do {            } while(0)
     299             : #endif
     300             : 
     301             : /* Macros for doing hexedit / tcpdump-like logging of memory regions.
     302             :    E.g.
     303             : 
     304             :      FD_LOG_NOTICE(( "cache line %016lx\n\t"
     305             :                      "%02x: " FD_LOG_HEX16_FMT "\n\t"
     306             :                      "%02x: " FD_LOG_HEX16_FMT "\n\t"
     307             :                      "%02x: " FD_LOG_HEX16_FMT "\n\t"
     308             :                      "%02x: " FD_LOG_HEX16_FMT,
     309             :                      (ulong)mem,
     310             :                       0U, FD_LOG_HEX16_FMT_ARGS( mem    ),
     311             :                      16U, FD_LOG_HEX16_FMT_ARGS( mem+16 ),
     312             :                      32U, FD_LOG_HEX16_FMT_ARGS( mem+32 ),
     313             :                      48U, FD_LOG_HEX16_FMT_ARGS( mem+48 ) ));
     314             : 
     315             :    would log something like:
     316             : 
     317             :      NOTICE  01-23 04:56:07.890123 45678 f0 0 src/foo.c(901): cache line 0123456789abcd00
     318             :              00: 00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f
     319             :              10: 10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f
     320             :              20: 20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f
     321             :              30: 30 31 32 33 34 35 36 37  38 39 3a 3b 3c 3d 3e 3f
     322             : 
     323             :    to the ephemeral log typically (and a more detailed message to the
     324             :    permanent log).  And similarly for the other log levels.  b should be
     325             :    safe against multiple evaluation. */
     326             : 
     327             : #define FD_LOG_HEX16_FMT "%02x %02x %02x %02x %02x %02x %02x %02x  %02x %02x %02x %02x %02x %02x %02x %02x"
     328             : #define FD_LOG_HEX16_FMT_ARGS(b)                                      \
     329             :   (uint)(((uchar const *)(b))[ 0]), (uint)(((uchar const *)(b))[ 1]), \
     330             :   (uint)(((uchar const *)(b))[ 2]), (uint)(((uchar const *)(b))[ 3]), \
     331             :   (uint)(((uchar const *)(b))[ 4]), (uint)(((uchar const *)(b))[ 5]), \
     332             :   (uint)(((uchar const *)(b))[ 6]), (uint)(((uchar const *)(b))[ 7]), \
     333             :   (uint)(((uchar const *)(b))[ 8]), (uint)(((uchar const *)(b))[ 9]), \
     334             :   (uint)(((uchar const *)(b))[10]), (uint)(((uchar const *)(b))[11]), \
     335             :   (uint)(((uchar const *)(b))[12]), (uint)(((uchar const *)(b))[13]), \
     336             :   (uint)(((uchar const *)(b))[14]), (uint)(((uchar const *)(b))[15])
     337             : 
     338             : #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"
     339             : #define FD_LOG_HEX20_FMT_ARGS(b)                                      \
     340             :   FD_LOG_HEX16_FMT_ARGS(b),                                           \
     341             :   (uint)(((uchar const *)(b))[16]), (uint)(((uchar const *)(b))[17]), \
     342             :   (uint)(((uchar const *)(b))[18]), (uint)(((uchar const *)(b))[19])
     343             : 
     344       26330 : #define FD_LOG_NAME_MAX (40UL)
     345             : 
     346             : FD_PROTOTYPES_BEGIN
     347             : 
     348             : /* APPLICATION LOGICAL IDENTIFIERS ************************************/
     349             : 
     350             : /* fd_log_app_id() returns an integer application id of the application
     351             :    to which the caller belongs.  An application id is intended, at a
     352             :    minimum, to uniquely identify all concurrently running applications
     353             :    in the enterprise.  This is cheap after the first call. */
     354             : 
     355             : FD_FN_PURE ulong fd_log_app_id( void );
     356             : 
     357             : /* fd_log_app() returns a non-NULL pointer to a cstr describing the
     358             :    application to which the caller belongs.  This is typically something
     359             :    provided to the caller when the caller started.  This is cheap after
     360             :    the first call and the lifetime of the returned string is infinite
     361             :    from the caller's point of view.  strlen(fd_log_app()) is in
     362             :    [1,FD_LOG_NAME_MAX). */
     363             : 
     364             : FD_FN_CONST char const * fd_log_app( void ); /* Pointer is CONST, cstr pointed at is PURE */
     365             : 
     366             : /* fd_log_thread_id() returns the caller's integer thread id.  A thread
     367             :    id is intended, at a minimum, to be unique over all concurrently
     368             :    running threads in the application.  This is cheap after the first
     369             :    call. */
     370             : 
     371             : ulong fd_log_thread_id( void );
     372             : 
     373             : /* fd_log_thread() returns a non-NULL pointer to a cstr describing the
     374             :    caller.  This defaults to some target specific default essentially
     375             :    determined at the caller's startup and can be explicitly set by the
     376             :    caller.  This is cheap after the first call within a thread and the
     377             :    lifetime of the returned pointer is until the next time the name is
     378             :    set or the caller terminates.  strlen(fd_log_thread()) is in
     379             :    [1,FD_LOG_NAME_MAX). */
     380             : 
     381             : char const * fd_log_thread( void );
     382             : 
     383             : /* fd_log_thread_set() sets the caller's description to the cstr
     384             :    pointed to by name.  A NULL name and/or an empty name ("") indicate
     385             :    to reset to the description that would have been assigned if the
     386             :    caller started at the time this is called.  name is not changed by
     387             :    the function and the fd_log does not retain any interest in name
     388             :    after return.  The actual resulting description will be truncated to
     389             :    a strlen of FD_LOG_NAME_MAX-1 if name is longer and potentially
     390             :    sanitized in other ways as necessary for the log. */
     391             : 
     392             : void
     393             : fd_log_thread_set( char const * name );
     394             : 
     395             : /* APPLICATION PHYSICAL IDENTIFIERS ***********************************/
     396             : 
     397             : /* fd_log_host_id() returns an integer host id of the host on which the
     398             :    caller is running.  A host id is intended, at a minimum, to uniquely
     399             :    identify a host enterprise wide.  This cheap after the first call. */
     400             : 
     401             : FD_FN_PURE ulong fd_log_host_id( void );
     402             : 
     403             : /* fd_log_host() returns a non-NULL pointer to a cstr describing the
     404             :    host on which the caller is running.  In simple cases, this defaults
     405             :    to the hostname.  In general cases, this is something provided to the
     406             :    caller at that caller's startup.  This is cheap after the first call
     407             :    and the lifetime of the returned string is infinite from the caller's
     408             :    point of view.  strlen(fd_log_host()) is in [1,FD_LOG_NAME_MAX). */
     409             : 
     410             : FD_FN_CONST char const * fd_log_host( void ); /* ptr is CONST, cstr pointed at is PURE */
     411             : 
     412             : /* fd_log_cpu_id() returns an integer cpu id of one of the cpus on
     413             :    where the caller was allowed to run when first called by a thread (or
     414             :    boot if the caller is the one that booted fd).  A cpu id is intended
     415             :    to uniquely identify a cpu on a host (e.g. for a host with
     416             :    homogeneous x86 cores, idx from /proc/cpuinfo).  This is cheap after
     417             :    the first call. */
     418             : 
     419             : ulong fd_log_cpu_id( void );
     420             : 
     421             : /* fd_log_cpu() returns a non-NULL pointer to a cstr describing the cpu
     422             :    on which the caller is running.  This defaults to some target
     423             :    specific default determined when first called on a thread (or boot if
     424             :    the caller is the one that booted fd).  This is cheap after the first
     425             :    call by a thread and the returned string is infinite from the
     426             :    caller's point of view.  strlen(fd_log_cpu()) is in
     427             :    [1,FD_LOG_NAME_MAX). */
     428             : 
     429             : char const * fd_log_cpu( void );
     430             : 
     431             : /* fd_log_cpu_set() sets the description of the cpu on which the caller
     432             :    is running on to the cstr pointed to by name.  A NULL name and/or an
     433             :    empty name ("") indicate to reset to the description that would have
     434             :    been assigned if the caller started at the time this is called.  name
     435             :    is not changed by the function and the fd_log does not retain any
     436             :    interest in name after return.  The actual resulting description will
     437             :    be truncated to a strlen of FD_LOG_NAME_MAX-1 if name is longer and
     438             :    potentially sanitized in other ways as necessary for the log. */
     439             : 
     440             : void
     441             : fd_log_cpu_set( char const * name );
     442             : 
     443             : /* THREAD GROUP RELATED IDENTIFIERS ***********************************/
     444             : 
     445             : /* fd_log_group_id() returns the thread group id of the thread group to
     446             :    which the caller belongs.  The thread group id is intended, at a
     447             :    minimum, to be unique over all thread groups on a host.  In simple
     448             :    cases, this is the OS pid of the process to which the caller belongs.
     449             :    In general cases, this is typically something provided to the caller
     450             :    when the caller started.  This is cheap after the first call.
     451             : 
     452             :    For sanity, this should be at least 2 (e.g. in POSIX group_id is
     453             :    equivalent to pid and pids<=1 are special such that a user is highly
     454             :    likely to assume group ids <= 1 are special). */
     455             : 
     456             : FD_FN_PURE ulong fd_log_group_id( void );
     457             : 
     458             : /* fd_log_group() returns a non-NULL pointer to a cstr describing the
     459             :    thread group to which the caller belongs.  In simple cases, this
     460             :    defaults to an abbreviated version of argv[0].  In general cases,
     461             :    this is typically something provided to the caller when the caller
     462             :    started.  This is cheap after the first call and the lifetime of the
     463             :    returned string is infinite from the caller's point of view.  The
     464             :    actual pointer and cstr is the same for all threads in the group. */
     465             : 
     466             : FD_FN_CONST char const * fd_log_group( void ); /* ptr is CONST, cstr pointed at is PURE */
     467             : 
     468             : /* fd_log_tid() returns the caller's thread group thread id.  A thread
     469             :    group thread id is intended, at a minimum, to be unique over all
     470             :    running threads in a thread group.  In simple cases, this is the
     471             :    caller's OS tid.  In general cases, this is typically something
     472             :    provided to the thread when that thread started.  This is cheap after
     473             :    the first call. */
     474             : 
     475             : ulong fd_log_tid( void );
     476             : 
     477             : /* fd_log_user_id() returns the user id of the thread group to which the
     478             :    caller belongs.  The user id is intended, at a minimum, to be unique
     479             :    over all users on a host.  In simple cases, this is the OS uid of the
     480             :    process to which the caller belongs.  In general cases, this is
     481             :    typically something provided to the caller when the caller started.
     482             :    This is cheap after the first call. */
     483             : 
     484             : FD_FN_PURE ulong fd_log_user_id( void );
     485             : 
     486             : /* fd_log_user() returns a non-NULL pointer to a cstr describing the
     487             :    user that created the thread group to which the caller belongs.  In
     488             :    simple cases, this defaults to the LOGNAME / login that started the
     489             :    process running the caller.  In general cases, this is something
     490             :    provided to the caller at that caller's startup.  This is cheap after
     491             :    the first call and the lifetime of the returned string is infinite
     492             :    from the caller's point of view.  strlen(fd_log_user()) is in
     493             :    [1,FD_LOG_NAME_MAX). */
     494             : 
     495             : FD_FN_CONST char const * fd_log_user( void ); /* ptr is CONST, cstr pointed at is PURE */
     496             : 
     497             : /* fd_log_group_id_query() returns the status of group_id.  Will be a
     498             :    FD_LOG_GROUP_ID_QUERY_* code.  Positive indicates live, zero
     499             :    indicates dead, negative indicates failure reason. */
     500             : 
     501           0 : #define FD_LOG_GROUP_ID_QUERY_LIVE  (1)  /* group_id is live */
     502           0 : #define FD_LOG_GROUP_ID_QUERY_DEAD  (0)  /* group_id is not live */
     503           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) */
     504           0 : #define FD_LOG_GROUP_ID_QUERY_PERM  (-2) /* query failed because caller lacks permissions */
     505           0 : #define FD_LOG_GROUP_ID_QUERY_FAIL  (-3) /* query failed for unknown reason (should not happen) */
     506             : 
     507             : int fd_log_group_id_query( ulong group_id );
     508             : 
     509             : /* FIXME: TID DESC? */
     510             : 
     511             : /* Build info APIs ****************************************************/
     512             : 
     513             : /* fd_log_build_info points in the caller's address space to the first
     514             :    byte of a memory region of size fd_log_build_info_sz containing a
     515             :    cstr with information about the environment in which the calling code
     516             :    was built.
     517             : 
     518             :    If build information was not available at compile time, the build
     519             :    info will be the empty string and size will be one.
     520             : 
     521             :    The value in this field is the last time the build info file was
     522             :    generated (such that, in a development compile-execute-debug
     523             :    iteration, the build info reflect the build environment since the
     524             :    last "make clean" or the developer manually deleted the build info).
     525             : 
     526             :    Code that is meant to be general purpose should not assume any
     527             :    particular format, contents, length, etc.  The build system,
     528             :    packaging manager, distribution manager, etc might external impose
     529             :    additional requirements on this string for application specific code
     530             :    though. */
     531             : 
     532             : extern char const  fd_log_build_info[] __attribute__((aligned(1)));
     533             : extern ulong const fd_log_build_info_sz; /* == strlen( fd_log_build_info ) + 1UL */
     534             : 
     535             : /* Logging helper APIs ************************************************/
     536             : 
     537             : /* fd_log_wallclock_host( NULL ) reads the host's wallclock as ns since
     538             :    the UNIX epoch GMT.  On x86, this uses clock_gettime/CLOCK_REALTIME
     539             :    under the hood and is reasonably cheap (~25-50 ns nowadays).  But it
     540             :    still may involve system calls under the hood and is much slower
     541             :    than, say, RTSDC. */
     542             : 
     543             : long fd_log_wallclock_host( void const * _ ); /* fd_clock_func_t compat */
     544             : 
     545             : /* fd_log_wallclock reads the log's timesource to get the ns since the
     546             :    UNIX epoch GMT.  By default, this is fd_log_wallclock_host but the
     547             :    thread group can be configures this to use an alternative time source
     548             :    if desired. */
     549             : 
     550             : long fd_log_wallclock( void ); /* FIXME: Make fd_clock_func_t compat */
     551             : 
     552             : /* fd_log_wallclock_set configures the log to use "clock( args )" as its
     553             :    time source.  This time source should report ns since the UNIX epoch
     554             :    GMT.  There should be no concurrent users of the log when this is
     555             :    called. */
     556             : 
     557             : void
     558             : fd_log_wallclock_set( fd_clock_func_t clock,
     559             :                       void const *    args );
     560             : 
     561             : /* fd_log_wallclock_cstr( t, buf ) pretty prints the wallclock
     562             :    measurement t as:
     563             :      "YYYY-MM-DD hh:mm:ss.nnnnnnnnn GMT+TZ".
     564             :    or in cases where conversion is not locally practical:
     565             :      "         ssssssssss.nnnnnnnnn s UNIX"
     566             :    buf must be a character buffer of at least
     567             :    FD_LOG_WALLCLOCK_CSTR_BUF_SZ bytes.  Returns buf and buf will be
     568             :    populated with the desired cstr on return. */
     569             : 
     570             : #define FD_LOG_WALLCLOCK_CSTR_BUF_SZ (37UL)
     571             : 
     572             : char *
     573             : fd_log_wallclock_cstr( long   t,
     574             :                        char * buf );
     575             : 
     576             : /* fd_log_sleep puts the calling thread to sleep for dt ns.  dt<=0 is
     577             :    assumed to be a sched_yield request.  Returns the amount of sleep
     578             :    remaining if the sleep was interrupted. */
     579             : 
     580             : long
     581             : fd_log_sleep( long dt );
     582             : 
     583             : /* fd_log_wait_until waits until fd_log_wallclock() is at least then.
     584             :    Returns the time on the clock when the wait ended (will be at least
     585             :    then).  This makes a best effort to be a good citizen and sleep /
     586             :    yield / hyperthreading friendly the caller while also being as
     587             :    precise on the wait as possible (i.e. limited by the overhead
     588             :    fd_log_wallclock).  That is, as the time remaining to wait decreases,
     589             :    the wait gets progressively more precise and CPU intensive.  If
     590             :    remaining is the number of ns remaining in the wait, then:
     591             : 
     592             :                remaining <~   1 us: spin
     593             :        1 us <~ remaining <~ 100 ms: hyper threading friendly spin
     594             :      100 ms <~ remaining <~   1  s: yielding spin
     595             :        1  s <~ remaining          : sleep until ~100 ms remaining
     596             : 
     597             :    If (as is usually the case) fd_log_sleep precision is much better
     598             :    than <<~100 ms accurate, FD_YIELD() delays take <<~100ms and
     599             :    FD_SPIN_PAUSE() << 1 us, the return value will be an accurate read of
     600             :    the fd_log_wallclock at the time of return and within the overhead of
     601             :    fd_log_wallclock. */
     602             : 
     603             : long
     604             : fd_log_wait_until( long then );
     605             : 
     606             : /* fd_log_flush() manually flushes the log (e.g. log a bunch of low
     607             :    priority messages and then flush to ensure the bunch gets written out
     608             :    before proceeding). */
     609             : 
     610             : void
     611             : fd_log_flush( void );
     612             : 
     613             : /* These all the logging levels to be configured at runtime.  These do
     614             :    no validation of there inputs so the values may not behave like the
     615             :    caller things (e.g. stderr<logfile will be treated as
     616             :    stderr==logfile, flush<stderr will be treated as flush==stderr,
     617             :    core<4 will be treated as 4).  colorize returns the colorization mode
     618             :    of the ephemeral log.  Currently, zero indicates no colorization of
     619             :    the ephemeral log and non-zero indicates to colorize it. */
     620             : 
     621             : int fd_log_colorize( void );
     622             : int fd_log_level_logfile ( void );
     623             : int fd_log_level_stderr  ( void );
     624             : int fd_log_level_flush   ( void );
     625             : int fd_log_level_core    ( void );
     626             : 
     627             : void fd_log_colorize_set     ( int mode  );
     628             : void fd_log_level_logfile_set( int level );
     629             : void fd_log_level_stderr_set ( int level );
     630             : void fd_log_level_flush_set  ( int level );
     631             : void fd_log_level_core_set   ( int level );
     632             : 
     633             : void fd_log_enable_signal_handler( void );
     634             : void fd_log_enable_unclean_exit( void );
     635             : 
     636             : /* These functions are for fd_log internal use only. */
     637             : 
     638             : void
     639             : fd_log_private_fprintf_0( int fd, char const * fmt, ... ) __attribute__((format(printf,2,3))); /* Type check the fmt string at compile time */
     640             : 
     641             : void
     642             : fd_log_private_fprintf_nolock_0( int fd, char const * fmt, ... ) __attribute__((format(printf,2,3))); /* Type check the fmt string at compile time */
     643             : 
     644             : char const *
     645             : fd_log_private_0( char const * fmt, ... ) __attribute__((format(printf,1,2))); /* Type check the fmt string at compile time */
     646             : 
     647             : void
     648             : fd_log_private_1( int          level,
     649             :                   long         now,
     650             :                   char const * file,
     651             :                   int          line,
     652             :                   char const * func,
     653             :                   char const * msg );
     654             : 
     655             : void
     656             : fd_log_private_2( int          level,
     657             :                   long         now,
     658             :                   char const * file,
     659             :                   int          line,
     660             :                   char const * func,
     661             :                   char const * msg ) __attribute__((noreturn)); /* Let compiler know this will not be returning */
     662             : 
     663             : void
     664             : fd_log_private_raw_2( char const * file,
     665             :                       int          line,
     666             :                       char const * func,
     667             :                       char const * msg ) __attribute__((noreturn)); /* Let compiler know this will not be returning */
     668             : 
     669             : char const *
     670             : fd_log_private_hexdump_msg( char const * tag,
     671             :                             void const * mem,
     672             :                             ulong        sz );
     673             : 
     674             : void
     675             : fd_log_private_boot( int *    pargc,
     676             :                      char *** pargv );
     677             : 
     678             : void
     679             : fd_log_private_boot_custom( int *        lock,
     680             :                             ulong        app_id,
     681             :                             char const * app,
     682             :                             ulong        thread_id,
     683             :                             char const * thread,
     684             :                             ulong        host_id,
     685             :                             char const * host,
     686             :                             ulong        cpu_id,
     687             :                             char const * cpu,
     688             :                             ulong        group_id,
     689             :                             char const * group,
     690             :                             ulong        tid,
     691             :                             ulong        user_id,
     692             :                             char const * user,
     693             :                             int          dedup,
     694             :                             int          colorize,
     695             :                             int          level_logfile,
     696             :                             int          level_stderr,
     697             :                             int          level_flush,
     698             :                             int          level_core,
     699             :                             int          log_fd,
     700             :                             char const * log_path );
     701             : 
     702             : void
     703             : fd_log_private_halt( void );
     704             : 
     705             : ulong fd_log_private_main_stack_sz( void ); /* Returns ulimit -s (if reasonable) on success, 0 on failure (logs details) */
     706             : 
     707             : ulong
     708             : fd_log_private_tid_default( void );
     709             : 
     710             : ulong
     711             : fd_log_private_cpu_id_default( void );
     712             : 
     713             : void
     714             : fd_log_private_stack_discover( ulong   stack_sz,  /* Size the stack is expected to be */
     715             :                                ulong * _stack0,   /* [*_stack0,*_stack1) is the caller's stack region (will have stack_sz */
     716             :                                ulong * _stack1 ); /* bytes) on success.  Both set to 0UL on failure (logs details). */
     717             : 
     718             : /* These are exposed to allow the user to override the values set at
     719             :    boot/halt time.  If these are used, they are usually a sign of
     720             :    working around a higher level architectural or operational issue. */
     721             : 
     722             : void fd_log_private_app_id_set   ( ulong app_id    );
     723             : void fd_log_private_thread_id_set( ulong thread_id );
     724             : void fd_log_private_host_id_set  ( ulong host_id   );
     725             : void fd_log_private_cpu_id_set   ( ulong cpu_id    );
     726             : void fd_log_private_group_id_set ( ulong group_id  );
     727             : void fd_log_private_tid_set      ( ulong tid       );
     728             : void fd_log_private_user_id_set  ( ulong user_id   );
     729             : 
     730             : void fd_log_private_app_set  ( char const * app   ); /* Not thread safe */
     731             : void fd_log_private_host_set ( char const * host  ); /* Not thread safe */
     732             : void fd_log_private_group_set( char const * group ); /* Not thread safe */
     733             : void fd_log_private_user_set ( char const * user  ); /* Not thread safe */
     734             : 
     735             : /* This is exposed to allow the user to know the expected file descriptor
     736             :    for filtering and security, it should never be used to actually write
     737             :    logs and that should be done by the functions in fd_log.h */
     738             : int fd_log_private_logfile_fd( void );
     739             : 
     740             : FD_PROTOTYPES_END
     741             : 
     742             : #endif /* HEADER_fd_src_util_log_fd_log_h */

Generated by: LCOV version 1.14