LCOV - code coverage report
Current view: top level - aws-c-common/include/aws/common - logging.h (source / functions) Hit Total Coverage
Test: all_fuzz.info Lines: 0 13 0.0 %
Date: 2021-04-23 16:28:21 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef AWS_COMMON_LOGGING_H
       2             : #define AWS_COMMON_LOGGING_H
       3             : 
       4             : /**
       5             :  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       6             :  * SPDX-License-Identifier: Apache-2.0.
       7             :  */
       8             : 
       9             : #include <aws/common/atomics.h>
      10             : #include <aws/common/common.h>
      11             : #include <aws/common/thread.h>
      12             : 
      13             : #define AWS_LOG_LEVEL_NONE 0
      14             : #define AWS_LOG_LEVEL_FATAL 1
      15             : #define AWS_LOG_LEVEL_ERROR 2
      16             : #define AWS_LOG_LEVEL_WARN 3
      17             : #define AWS_LOG_LEVEL_INFO 4
      18             : #define AWS_LOG_LEVEL_DEBUG 5
      19             : #define AWS_LOG_LEVEL_TRACE 6
      20             : 
      21             : /**
      22             :  * Controls what log calls pass through the logger and what log calls get filtered out.
      23             :  * If a log level has a value of X, then all log calls using a level <= X will appear, while
      24             :  * those using a value > X will not occur.
      25             :  *
      26             :  * You can filter both dynamically (by setting the log level on the logger object) or statically
      27             :  * (by defining AWS_STATIC_LOG_LEVEL to be an appropriate integer module-wide).  Statically filtered
      28             :  * log calls will be completely compiled out but require a rebuild if you want to get more detail
      29             :  * about what's happening.
      30             :  */
      31             : enum aws_log_level {
      32             :     AWS_LL_NONE = AWS_LOG_LEVEL_NONE,
      33             :     AWS_LL_FATAL = AWS_LOG_LEVEL_FATAL,
      34             :     AWS_LL_ERROR = AWS_LOG_LEVEL_ERROR,
      35             :     AWS_LL_WARN = AWS_LOG_LEVEL_WARN,
      36             :     AWS_LL_INFO = AWS_LOG_LEVEL_INFO,
      37             :     AWS_LL_DEBUG = AWS_LOG_LEVEL_DEBUG,
      38             :     AWS_LL_TRACE = AWS_LOG_LEVEL_TRACE,
      39             : 
      40             :     AWS_LL_COUNT
      41             : };
      42             : 
      43             : /**
      44             :  * Log subject is a way of designating the topic of logging.
      45             :  *
      46             :  * The general idea is to support a finer-grained approach to log level control.  The primary use case
      47             :  * is for situations that require more detailed logging within a specific domain, where enabling that detail
      48             :  * globally leads to an untenable flood of information.
      49             :  *
      50             :  * For example, enable TRACE logging for tls-related log statements (handshake binary payloads), but
      51             :  * only WARN logging everywhere else (because http payloads would blow up the log files).
      52             :  *
      53             :  * Log subject is an enum similar to aws error: each library has its own value-space and someone is
      54             :  * responsible for registering the value <-> string connections.
      55             :  */
      56             : typedef uint32_t aws_log_subject_t;
      57             : 
      58             : /* Each library gets space for 2^^10 log subject entries */
      59           0 : #define AWS_LOG_SUBJECT_STRIDE_BITS 10
      60           0 : #define AWS_LOG_SUBJECT_STRIDE (1U << AWS_LOG_SUBJECT_STRIDE_BITS)
      61             : #define AWS_LOG_SUBJECT_BEGIN_RANGE(x) ((x)*AWS_LOG_SUBJECT_STRIDE)
      62             : #define AWS_LOG_SUBJECT_END_RANGE(x) (((x) + 1) * AWS_LOG_SUBJECT_STRIDE - 1)
      63             : 
      64             : struct aws_log_subject_info {
      65             :     aws_log_subject_t subject_id;
      66             :     const char *subject_name;
      67             :     const char *subject_description;
      68             : };
      69             : 
      70             : #define DEFINE_LOG_SUBJECT_INFO(id, name, desc)                                                                        \
      71             :     { .subject_id = (id), .subject_name = (name), .subject_description = (desc) }
      72             : 
      73             : struct aws_log_subject_info_list {
      74             :     struct aws_log_subject_info *subject_list;
      75             :     size_t count;
      76             : };
      77             : 
      78             : enum aws_common_log_subject {
      79             :     AWS_LS_COMMON_GENERAL = AWS_LOG_SUBJECT_BEGIN_RANGE(AWS_C_COMMON_PACKAGE_ID),
      80             :     AWS_LS_COMMON_TASK_SCHEDULER,
      81             :     AWS_LS_COMMON_THREAD,
      82             :     AWS_LS_COMMON_MEMTRACE,
      83             :     AWS_LS_COMMON_XML_PARSER,
      84             : 
      85             :     AWS_LS_COMMON_LAST = AWS_LOG_SUBJECT_END_RANGE(AWS_C_COMMON_PACKAGE_ID)
      86             : };
      87             : 
      88             : struct aws_logger;
      89             : struct aws_log_formatter;
      90             : struct aws_log_channel;
      91             : struct aws_log_writer;
      92             : 
      93             : /**
      94             :  * We separate the log level function from the log call itself so that we can do the filter check in the macros (see
      95             :  * below)
      96             :  *
      97             :  * By doing so, we make it so that the variadic format arguments are not even evaluated if the filter check does not
      98             :  * succeed.
      99             :  */
     100             : struct aws_logger_vtable {
     101             :     int (*const log)(
     102             :         struct aws_logger *logger,
     103             :         enum aws_log_level log_level,
     104             :         aws_log_subject_t subject,
     105             :         const char *format,
     106             :         ...)
     107             : #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
     108             :         __attribute__((format(printf, 4, 5)))
     109             : #endif /* non-ms compilers: TODO - find out what versions format support was added in */
     110             :         ;
     111             :     enum aws_log_level (*const get_log_level)(struct aws_logger *logger, aws_log_subject_t subject);
     112             :     void (*const clean_up)(struct aws_logger *logger);
     113             :     int (*set_log_level)(struct aws_logger *logger, enum aws_log_level);
     114             : };
     115             : 
     116             : struct aws_logger {
     117             :     struct aws_logger_vtable *vtable;
     118             :     struct aws_allocator *allocator;
     119             :     void *p_impl;
     120             : };
     121             : 
     122             : /**
     123             :  * The base formatted logging macro that all other formatted logging macros resolve to.
     124             :  * Checks for a logger and filters based on log level.
     125             :  *
     126             :  */
     127             : #define AWS_LOGF(log_level, subject, ...)                                                                              \
     128           0 :     {                                                                                                                  \
     129           0 :         AWS_ASSERT(log_level > 0);                                                                                     \
     130           0 :         struct aws_logger *logger = aws_logger_get();                                                                  \
     131           0 :         if (logger != NULL && logger->vtable->get_log_level(logger, (subject)) >= (log_level)) {                       \
     132           0 :             logger->vtable->log(logger, log_level, subject, __VA_ARGS__);                                              \
     133           0 :         }                                                                                                              \
     134           0 :     }
     135             : 
     136             : /**
     137             :  * LOGF_<level> variants for each level.  These are what should be used directly to do all logging.
     138             :  *
     139             :  * i.e.
     140             :  *
     141             :  * LOGF_FATAL("Device \"%s\" not found", device->name);
     142             :  *
     143             :  *
     144             :  * Later we will likely expose Subject-aware variants
     145             :  */
     146             : #if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_FATAL)
     147             : #    define AWS_LOGF_FATAL(subject, ...) AWS_LOGF(AWS_LL_FATAL, subject, __VA_ARGS__)
     148             : #else
     149             : #    define AWS_LOGF_FATAL(subject, ...)
     150             : #endif
     151             : 
     152             : #if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_ERROR)
     153           0 : #    define AWS_LOGF_ERROR(subject, ...) AWS_LOGF(AWS_LL_ERROR, subject, __VA_ARGS__)
     154             : #else
     155             : #    define AWS_LOGF_ERROR(subject, ...)
     156             : #endif
     157             : 
     158             : #if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_WARN)
     159           0 : #    define AWS_LOGF_WARN(subject, ...) AWS_LOGF(AWS_LL_WARN, subject, __VA_ARGS__)
     160             : #else
     161             : #    define AWS_LOGF_WARN(subject, ...)
     162             : #endif
     163             : 
     164             : #if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_INFO)
     165           0 : #    define AWS_LOGF_INFO(subject, ...) AWS_LOGF(AWS_LL_INFO, subject, __VA_ARGS__)
     166             : #else
     167             : #    define AWS_LOGF_INFO(subject, ...)
     168             : #endif
     169             : 
     170             : #if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_DEBUG)
     171             : #    define AWS_LOGF_DEBUG(subject, ...) AWS_LOGF(AWS_LL_DEBUG, subject, __VA_ARGS__)
     172             : #else
     173             : #    define AWS_LOGF_DEBUG(subject, ...)
     174             : #endif
     175             : 
     176             : #if !defined(AWS_STATIC_LOG_LEVEL) || (AWS_STATIC_LOG_LEVEL >= AWS_LOG_LEVEL_TRACE)
     177           0 : #    define AWS_LOGF_TRACE(subject, ...) AWS_LOGF(AWS_LL_TRACE, subject, __VA_ARGS__)
     178             : #else
     179             : #    define AWS_LOGF_TRACE(subject, ...)
     180             : #endif
     181             : 
     182             : /*
     183             :  * Standard logger implementation composing three sub-components:
     184             :  *
     185             :  * The formatter takes var args input from the user and produces a formatted log line
     186             :  * The writer takes a formatted log line and outputs it somewhere
     187             :  * The channel is the transport between the two
     188             :  */
     189             : struct aws_logger_pipeline {
     190             :     struct aws_log_formatter *formatter;
     191             :     struct aws_log_channel *channel;
     192             :     struct aws_log_writer *writer;
     193             :     struct aws_allocator *allocator;
     194             :     struct aws_atomic_var level;
     195             : };
     196             : 
     197             : /**
     198             :  * Options for aws_logger_init_standard().
     199             :  * Set `filename` to open a file for logging and close it when the logger cleans up.
     200             :  * Set `file` to use a file that is already open, such as `stderr` or `stdout`.
     201             :  */
     202             : struct aws_logger_standard_options {
     203             :     enum aws_log_level level;
     204             :     const char *filename;
     205             :     FILE *file;
     206             : };
     207             : 
     208             : AWS_EXTERN_C_BEGIN
     209             : 
     210             : /**
     211             :  * Sets the aws logger used globally across the process.  Not thread-safe.  Must only be called once.
     212             :  */
     213             : AWS_COMMON_API
     214             : void aws_logger_set(struct aws_logger *logger);
     215             : 
     216             : /**
     217             :  * Gets the aws logger used globally across the process.
     218             :  */
     219             : AWS_COMMON_API
     220             : struct aws_logger *aws_logger_get(void);
     221             : 
     222             : /**
     223             :  * Cleans up all resources used by the logger; simply invokes the clean_up v-function
     224             :  */
     225             : AWS_COMMON_API
     226             : void aws_logger_clean_up(struct aws_logger *logger);
     227             : 
     228             : /**
     229             :  * Sets the current logging level for the logger.  Loggers are not require to support this.
     230             :  * @param logger logger to set the log level for
     231             :  * @param level new log level for the logger
     232             :  * @return AWS_OP_SUCCESS if the level was successfully set, AWS_OP_ERR otherwise
     233             :  */
     234             : AWS_COMMON_API
     235             : int aws_logger_set_log_level(struct aws_logger *logger, enum aws_log_level level);
     236             : 
     237             : /**
     238             :  * Converts a log level to a c-string constant.  Intended primarily to support building log lines that
     239             :  * include the level in them, i.e.
     240             :  *
     241             :  * [ERROR] 10:34:54.642 01-31-19 - Json parse error....
     242             :  */
     243             : AWS_COMMON_API
     244             : int aws_log_level_to_string(enum aws_log_level log_level, const char **level_string);
     245             : 
     246             : /**
     247             :  * Converts a c-string constant to a log level value.  Uses case-insensitive comparison
     248             :  * and simply iterates all possibilities until a match or nothing remains.  If no match
     249             :  * is found, AWS_OP_ERR is returned.
     250             :  */
     251             : AWS_COMMON_API
     252             : int aws_string_to_log_level(const char *level_string, enum aws_log_level *log_level);
     253             : 
     254             : /**
     255             :  * Converts an aws_thread_id_t to a c-string.  For portability, aws_thread_id_t
     256             :  * must not be printed directly.  Intended primarily to support building log
     257             :  * lines that include the thread id in them.  The parameter `buffer` must
     258             :  * point-to a char buffer of length `bufsz == AWS_THREAD_ID_T_REPR_BUFSZ`.  The
     259             :  * thread id representation is returned in `buffer`.
     260             :  */
     261             : AWS_COMMON_API
     262             : int aws_thread_id_t_to_string(aws_thread_id_t thread_id, char *buffer, size_t bufsz);
     263             : 
     264             : /**
     265             :  * Get subject name from log subject.
     266             :  */
     267             : AWS_COMMON_API
     268             : const char *aws_log_subject_name(aws_log_subject_t subject);
     269             : 
     270             : /**
     271             :  * Connects log subject strings with log subject integer values
     272             :  */
     273             : AWS_COMMON_API
     274             : void aws_register_log_subject_info_list(struct aws_log_subject_info_list *log_subject_list);
     275             : 
     276             : /**
     277             :  * Disconnects log subject strings with log subject integer values
     278             :  */
     279             : AWS_COMMON_API
     280             : void aws_unregister_log_subject_info_list(struct aws_log_subject_info_list *log_subject_list);
     281             : 
     282             : /*
     283             :  * Initializes a pipeline logger that is built from the default formatter, a background thread-based channel, and
     284             :  * a file writer.  The default logger in almost all circumstances.
     285             :  */
     286             : AWS_COMMON_API
     287             : int aws_logger_init_standard(
     288             :     struct aws_logger *logger,
     289             :     struct aws_allocator *allocator,
     290             :     struct aws_logger_standard_options *options);
     291             : 
     292             : /*
     293             :  * Initializes a pipeline logger from components that have already been initialized.  This is not an ownership transfer.
     294             :  * After the pipeline logger is cleaned up, the components will have to manually be cleaned up by the user.
     295             :  */
     296             : AWS_COMMON_API
     297             : int aws_logger_init_from_external(
     298             :     struct aws_logger *logger,
     299             :     struct aws_allocator *allocator,
     300             :     struct aws_log_formatter *formatter,
     301             :     struct aws_log_channel *channel,
     302             :     struct aws_log_writer *writer,
     303             :     enum aws_log_level level);
     304             : 
     305             : /*
     306             :  * Pipeline logger vtable for custom configurations
     307             :  */
     308             : AWS_COMMON_API
     309             : extern struct aws_logger_vtable g_pipeline_logger_owned_vtable;
     310             : 
     311             : /*
     312             :  * Initializes a logger that does not perform any allocation during logging.  Log lines larger than the internal
     313             :  * constant are truncated.  Formatting matches the standard logger.  Used for memory tracing logging.
     314             :  */
     315             : AWS_COMMON_API
     316             : int aws_logger_init_noalloc(
     317             :     struct aws_logger *logger,
     318             :     struct aws_allocator *allocator,
     319             :     struct aws_logger_standard_options *options);
     320             : 
     321             : AWS_EXTERN_C_END
     322             : 
     323             : #endif /* AWS_COMMON_LOGGING_H */

Generated by: LCOV version 1.13