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

          Line data    Source code
       1             : /**
       2             :  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
       3             :  * SPDX-License-Identifier: Apache-2.0.
       4             :  */
       5             : 
       6             : #include <aws/common/logging.h>
       7             : 
       8             : #include <aws/common/log_channel.h>
       9             : #include <aws/common/log_formatter.h>
      10             : #include <aws/common/log_writer.h>
      11             : #include <aws/common/mutex.h>
      12             : #include <aws/common/string.h>
      13             : 
      14             : #include <errno.h>
      15             : #include <stdarg.h>
      16             : 
      17             : #if _MSC_VER
      18             : #    pragma warning(disable : 4204) /* non-constant aggregate initializer */
      19             : #    pragma warning(disable : 4996) /* Disable warnings about fopen() being insecure */
      20             : #endif
      21             : 
      22             : /*
      23             :  * Null logger implementation
      24             :  */
      25           0 : static enum aws_log_level s_null_logger_get_log_level(struct aws_logger *logger, aws_log_subject_t subject) {
      26           0 :     (void)logger;
      27           0 :     (void)subject;
      28           0 : 
      29           0 :     return AWS_LL_NONE;
      30           0 : }
      31             : 
      32             : static int s_null_logger_log(
      33             :     struct aws_logger *logger,
      34             :     enum aws_log_level log_level,
      35             :     aws_log_subject_t subject,
      36             :     const char *format,
      37           0 :     ...) {
      38           0 : 
      39           0 :     (void)logger;
      40           0 :     (void)log_level;
      41           0 :     (void)subject;
      42           0 :     (void)format;
      43           0 : 
      44           0 :     return AWS_OP_SUCCESS;
      45           0 : }
      46             : 
      47           0 : static void s_null_logger_clean_up(struct aws_logger *logger) {
      48           0 :     (void)logger;
      49           0 : }
      50             : 
      51             : static struct aws_logger_vtable s_null_vtable = {
      52             :     .get_log_level = s_null_logger_get_log_level,
      53             :     .log = s_null_logger_log,
      54             :     .clean_up = s_null_logger_clean_up,
      55             : };
      56             : 
      57             : static struct aws_logger s_null_logger = {
      58             :     .vtable = &s_null_vtable,
      59             :     .allocator = NULL,
      60             :     .p_impl = NULL,
      61             : };
      62             : 
      63             : /*
      64             :  * Pipeline logger implementation
      65             :  */
      66           0 : static void s_aws_logger_pipeline_owned_clean_up(struct aws_logger *logger) {
      67           0 :     struct aws_logger_pipeline *impl = logger->p_impl;
      68           0 : 
      69           0 :     AWS_ASSERT(impl->channel->vtable->clean_up != NULL);
      70           0 :     (impl->channel->vtable->clean_up)(impl->channel);
      71           0 : 
      72           0 :     AWS_ASSERT(impl->formatter->vtable->clean_up != NULL);
      73           0 :     (impl->formatter->vtable->clean_up)(impl->formatter);
      74           0 : 
      75           0 :     AWS_ASSERT(impl->writer->vtable->clean_up != NULL);
      76           0 :     (impl->writer->vtable->clean_up)(impl->writer);
      77           0 : 
      78           0 :     aws_mem_release(impl->allocator, impl->channel);
      79           0 :     aws_mem_release(impl->allocator, impl->formatter);
      80           0 :     aws_mem_release(impl->allocator, impl->writer);
      81           0 : 
      82           0 :     aws_mem_release(impl->allocator, impl);
      83           0 : }
      84             : 
      85             : /*
      86             :  * Pipeline logger implementation
      87             :  */
      88             : static int s_aws_logger_pipeline_log(
      89             :     struct aws_logger *logger,
      90             :     enum aws_log_level log_level,
      91             :     aws_log_subject_t subject,
      92             :     const char *format,
      93           0 :     ...) {
      94           0 :     va_list format_args;
      95           0 :     va_start(format_args, format);
      96           0 : 
      97           0 :     struct aws_logger_pipeline *impl = logger->p_impl;
      98           0 :     struct aws_string *output = NULL;
      99           0 : 
     100           0 :     AWS_ASSERT(impl->formatter->vtable->format != NULL);
     101           0 :     int result = (impl->formatter->vtable->format)(impl->formatter, &output, log_level, subject, format, format_args);
     102           0 : 
     103           0 :     va_end(format_args);
     104           0 : 
     105           0 :     if (result != AWS_OP_SUCCESS || output == NULL) {
     106           0 :         return AWS_OP_ERR;
     107           0 :     }
     108           0 : 
     109           0 :     AWS_ASSERT(impl->channel->vtable->send != NULL);
     110           0 :     if ((impl->channel->vtable->send)(impl->channel, output)) {
     111           0 :         /*
     112           0 :          * failure to send implies failure to transfer ownership
     113           0 :          */
     114           0 :         aws_string_destroy(output);
     115           0 :         return AWS_OP_ERR;
     116           0 :     }
     117           0 : 
     118           0 :     return AWS_OP_SUCCESS;
     119           0 : }
     120             : 
     121           0 : static enum aws_log_level s_aws_logger_pipeline_get_log_level(struct aws_logger *logger, aws_log_subject_t subject) {
     122           0 :     (void)subject;
     123           0 : 
     124           0 :     struct aws_logger_pipeline *impl = logger->p_impl;
     125           0 : 
     126           0 :     return (enum aws_log_level)aws_atomic_load_int(&impl->level);
     127           0 : }
     128             : 
     129           0 : static int s_aws_logger_pipeline_set_log_level(struct aws_logger *logger, enum aws_log_level level) {
     130           0 :     struct aws_logger_pipeline *impl = logger->p_impl;
     131           0 : 
     132           0 :     aws_atomic_store_int(&impl->level, (size_t)level);
     133           0 : 
     134           0 :     return AWS_OP_SUCCESS;
     135           0 : }
     136             : 
     137             : struct aws_logger_vtable g_pipeline_logger_owned_vtable = {
     138             :     .get_log_level = s_aws_logger_pipeline_get_log_level,
     139             :     .log = s_aws_logger_pipeline_log,
     140             :     .clean_up = s_aws_logger_pipeline_owned_clean_up,
     141             :     .set_log_level = s_aws_logger_pipeline_set_log_level,
     142             : };
     143             : 
     144             : int aws_logger_init_standard(
     145             :     struct aws_logger *logger,
     146             :     struct aws_allocator *allocator,
     147           0 :     struct aws_logger_standard_options *options) {
     148           0 : 
     149             : #ifdef ANDROID
     150             :     (void)options;
     151             :     extern int aws_logger_init_logcat(
     152             :         struct aws_logger *, struct aws_allocator *, struct aws_logger_standard_options *);
     153             :     return aws_logger_init_logcat(logger, allocator, options);
     154             : #endif
     155             : 
     156           0 :     struct aws_logger_pipeline *impl = aws_mem_calloc(allocator, 1, sizeof(struct aws_logger_pipeline));
     157           0 :     if (impl == NULL) {
     158           0 :         return AWS_OP_ERR;
     159           0 :     }
     160           0 : 
     161           0 :     struct aws_log_writer *writer = aws_mem_acquire(allocator, sizeof(struct aws_log_writer));
     162           0 :     if (writer == NULL) {
     163           0 :         goto on_allocate_writer_failure;
     164           0 :     }
     165           0 : 
     166           0 :     struct aws_log_writer_file_options file_writer_options = {
     167           0 :         .filename = options->filename,
     168           0 :         .file = options->file,
     169           0 :     };
     170           0 : 
     171           0 :     if (aws_log_writer_init_file(writer, allocator, &file_writer_options)) {
     172           0 :         goto on_init_writer_failure;
     173           0 :     }
     174           0 : 
     175           0 :     struct aws_log_formatter *formatter = aws_mem_acquire(allocator, sizeof(struct aws_log_formatter));
     176           0 :     if (formatter == NULL) {
     177           0 :         goto on_allocate_formatter_failure;
     178           0 :     }
     179           0 : 
     180           0 :     struct aws_log_formatter_standard_options formatter_options = {.date_format = AWS_DATE_FORMAT_ISO_8601};
     181           0 : 
     182           0 :     if (aws_log_formatter_init_default(formatter, allocator, &formatter_options)) {
     183           0 :         goto on_init_formatter_failure;
     184           0 :     }
     185           0 : 
     186           0 :     struct aws_log_channel *channel = aws_mem_acquire(allocator, sizeof(struct aws_log_channel));
     187           0 :     if (channel == NULL) {
     188           0 :         goto on_allocate_channel_failure;
     189           0 :     }
     190           0 : 
     191           0 :     if (aws_log_channel_init_background(channel, allocator, writer) == AWS_OP_SUCCESS) {
     192           0 :         impl->formatter = formatter;
     193           0 :         impl->channel = channel;
     194           0 :         impl->writer = writer;
     195           0 :         impl->allocator = allocator;
     196           0 :         aws_atomic_store_int(&impl->level, (size_t)options->level);
     197           0 : 
     198           0 :         logger->vtable = &g_pipeline_logger_owned_vtable;
     199           0 :         logger->allocator = allocator;
     200           0 :         logger->p_impl = impl;
     201           0 : 
     202           0 :         return AWS_OP_SUCCESS;
     203           0 :     }
     204           0 : 
     205           0 :     aws_mem_release(allocator, channel);
     206           0 : 
     207           0 : on_allocate_channel_failure:
     208           0 :     aws_log_formatter_clean_up(formatter);
     209           0 : 
     210           0 : on_init_formatter_failure:
     211           0 :     aws_mem_release(allocator, formatter);
     212           0 : 
     213           0 : on_allocate_formatter_failure:
     214           0 :     aws_log_writer_clean_up(writer);
     215           0 : 
     216           0 : on_init_writer_failure:
     217           0 :     aws_mem_release(allocator, writer);
     218           0 : 
     219           0 : on_allocate_writer_failure:
     220           0 :     aws_mem_release(allocator, impl);
     221           0 : 
     222           0 :     return AWS_OP_ERR;
     223           0 : }
     224             : 
     225             : /*
     226             :  * Pipeline logger implementation where all the components are externally owned.  No clean up
     227             :  * is done on the components.  Useful for tests where components are on the stack and often mocked.
     228             :  */
     229           0 : static void s_aws_pipeline_logger_unowned_clean_up(struct aws_logger *logger) {
     230           0 :     struct aws_logger_pipeline *impl = (struct aws_logger_pipeline *)logger->p_impl;
     231           0 : 
     232           0 :     aws_mem_release(impl->allocator, impl);
     233           0 : }
     234             : 
     235             : static struct aws_logger_vtable s_pipeline_logger_unowned_vtable = {
     236             :     .get_log_level = s_aws_logger_pipeline_get_log_level,
     237             :     .log = s_aws_logger_pipeline_log,
     238             :     .clean_up = s_aws_pipeline_logger_unowned_clean_up,
     239             :     .set_log_level = s_aws_logger_pipeline_set_log_level,
     240             : };
     241             : 
     242             : int aws_logger_init_from_external(
     243             :     struct aws_logger *logger,
     244             :     struct aws_allocator *allocator,
     245             :     struct aws_log_formatter *formatter,
     246             :     struct aws_log_channel *channel,
     247             :     struct aws_log_writer *writer,
     248           0 :     enum aws_log_level level) {
     249           0 : 
     250           0 :     struct aws_logger_pipeline *impl = aws_mem_acquire(allocator, sizeof(struct aws_logger_pipeline));
     251           0 : 
     252           0 :     if (impl == NULL) {
     253           0 :         return AWS_OP_ERR;
     254           0 :     }
     255           0 : 
     256           0 :     impl->formatter = formatter;
     257           0 :     impl->channel = channel;
     258           0 :     impl->writer = writer;
     259           0 :     impl->allocator = allocator;
     260           0 :     aws_atomic_store_int(&impl->level, (size_t)level);
     261           0 : 
     262           0 :     logger->vtable = &s_pipeline_logger_unowned_vtable;
     263           0 :     logger->allocator = allocator;
     264           0 :     logger->p_impl = impl;
     265           0 : 
     266           0 :     return AWS_OP_SUCCESS;
     267           0 : }
     268             : 
     269             : /*
     270             :  * Global API
     271             :  */
     272             : static struct aws_logger *s_root_logger_ptr = &s_null_logger;
     273             : 
     274           0 : void aws_logger_set(struct aws_logger *logger) {
     275           0 :     if (logger != NULL) {
     276           0 :         s_root_logger_ptr = logger;
     277           0 :     } else {
     278           0 :         s_root_logger_ptr = &s_null_logger;
     279           0 :     }
     280           0 : }
     281             : 
     282           0 : struct aws_logger *aws_logger_get(void) {
     283           0 :     return s_root_logger_ptr;
     284           0 : }
     285             : 
     286           0 : void aws_logger_clean_up(struct aws_logger *logger) {
     287           0 :     AWS_ASSERT(logger->vtable->clean_up != NULL);
     288           0 : 
     289           0 :     logger->vtable->clean_up(logger);
     290           0 : }
     291             : 
     292             : static const char *s_log_level_strings[AWS_LL_COUNT] = {"NONE", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"};
     293             : 
     294           0 : int aws_log_level_to_string(enum aws_log_level log_level, const char **level_string) {
     295           0 :     AWS_ERROR_PRECONDITION(log_level < AWS_LL_COUNT);
     296           0 : 
     297           0 :     if (level_string != NULL) {
     298           0 :         *level_string = s_log_level_strings[log_level];
     299           0 :     }
     300           0 : 
     301           0 :     return AWS_OP_SUCCESS;
     302           0 : }
     303             : 
     304           0 : int aws_string_to_log_level(const char *level_string, enum aws_log_level *log_level) {
     305           0 :     if (level_string != NULL && log_level != NULL) {
     306           0 :         size_t level_length = strlen(level_string);
     307           0 :         for (int i = 0; i < AWS_LL_COUNT; ++i) {
     308           0 :             if (aws_array_eq_c_str_ignore_case(level_string, level_length, s_log_level_strings[i])) {
     309           0 :                 *log_level = i;
     310           0 :                 return AWS_OP_SUCCESS;
     311           0 :             }
     312           0 :         }
     313           0 :     }
     314           0 : 
     315           0 :     aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
     316           0 :     return AWS_OP_ERR;
     317           0 : }
     318             : 
     319           0 : int aws_thread_id_t_to_string(aws_thread_id_t thread_id, char *buffer, size_t bufsz) {
     320           0 :     AWS_ERROR_PRECONDITION(AWS_THREAD_ID_T_REPR_BUFSZ == bufsz);
     321           0 :     AWS_ERROR_PRECONDITION(buffer && AWS_MEM_IS_WRITABLE(buffer, bufsz));
     322           0 :     size_t current_index = 0;
     323           0 :     unsigned char *bytes = (unsigned char *)&thread_id;
     324           0 :     for (size_t i = sizeof(aws_thread_id_t); i != 0; --i) {
     325           0 :         unsigned char c = bytes[i - 1];
     326           0 :         int written = snprintf(buffer + current_index, bufsz - current_index, "%02x", c);
     327           0 :         if (written < 0) {
     328           0 :             return AWS_OP_ERR;
     329           0 :         }
     330           0 :         current_index += written;
     331           0 :         if (bufsz <= current_index) {
     332           0 :             return AWS_OP_ERR;
     333           0 :         }
     334           0 :     }
     335           0 :     return AWS_OP_SUCCESS;
     336           0 : }
     337             : 
     338           0 : #define AWS_LOG_SUBJECT_SPACE_MASK (AWS_LOG_SUBJECT_STRIDE - 1)
     339             : 
     340             : static const uint32_t S_MAX_LOG_SUBJECT = AWS_LOG_SUBJECT_STRIDE * AWS_PACKAGE_SLOTS - 1;
     341             : 
     342             : static const struct aws_log_subject_info_list *volatile s_log_subject_slots[AWS_PACKAGE_SLOTS] = {0};
     343             : 
     344           0 : static const struct aws_log_subject_info *s_get_log_subject_info_by_id(aws_log_subject_t subject) {
     345           0 :     if (subject > S_MAX_LOG_SUBJECT) {
     346           0 :         return NULL;
     347           0 :     }
     348           0 : 
     349           0 :     uint32_t slot_index = subject >> AWS_LOG_SUBJECT_STRIDE_BITS;
     350           0 :     uint32_t subject_index = subject & AWS_LOG_SUBJECT_SPACE_MASK;
     351           0 : 
     352           0 :     const struct aws_log_subject_info_list *subject_slot = s_log_subject_slots[slot_index];
     353           0 : 
     354           0 :     if (!subject_slot || subject_index >= subject_slot->count) {
     355           0 :         return NULL;
     356           0 :     }
     357           0 : 
     358           0 :     return &subject_slot->subject_list[subject_index];
     359           0 : }
     360             : 
     361           0 : const char *aws_log_subject_name(aws_log_subject_t subject) {
     362           0 :     const struct aws_log_subject_info *subject_info = s_get_log_subject_info_by_id(subject);
     363           0 : 
     364           0 :     if (subject_info != NULL) {
     365           0 :         return subject_info->subject_name;
     366           0 :     }
     367           0 : 
     368           0 :     return "Unknown";
     369           0 : }
     370             : 
     371           0 : void aws_register_log_subject_info_list(struct aws_log_subject_info_list *log_subject_list) {
     372           0 :     /*
     373           0 :      * We're not so worried about these asserts being removed in an NDEBUG build
     374           0 :      * - we'll either segfault immediately (for the first two) or for the count
     375           0 :      * assert, the registration will be ineffective.
     376           0 :      */
     377           0 :     AWS_FATAL_ASSERT(log_subject_list);
     378           0 :     AWS_FATAL_ASSERT(log_subject_list->subject_list);
     379           0 :     AWS_FATAL_ASSERT(log_subject_list->count);
     380           0 : 
     381           0 :     const uint32_t min_range = log_subject_list->subject_list[0].subject_id;
     382           0 :     const uint32_t slot_index = min_range >> AWS_LOG_SUBJECT_STRIDE_BITS;
     383           0 : 
     384           0 :     if (slot_index >= AWS_PACKAGE_SLOTS) {
     385           0 :         /* This is an NDEBUG build apparently. Kill the process rather than
     386           0 :          * corrupting heap. */
     387           0 :         fprintf(stderr, "Bad log subject slot index 0x%016x\n", slot_index);
     388           0 :         abort();
     389           0 :     }
     390           0 : 
     391           0 :     s_log_subject_slots[slot_index] = log_subject_list;
     392           0 : }
     393             : 
     394           0 : void aws_unregister_log_subject_info_list(struct aws_log_subject_info_list *log_subject_list) {
     395           0 :     /*
     396           0 :      * We're not so worried about these asserts being removed in an NDEBUG build
     397           0 :      * - we'll either segfault immediately (for the first two) or for the count
     398           0 :      * assert, the registration will be ineffective.
     399           0 :      */
     400           0 :     AWS_FATAL_ASSERT(log_subject_list);
     401           0 :     AWS_FATAL_ASSERT(log_subject_list->subject_list);
     402           0 :     AWS_FATAL_ASSERT(log_subject_list->count);
     403           0 : 
     404           0 :     const uint32_t min_range = log_subject_list->subject_list[0].subject_id;
     405           0 :     const uint32_t slot_index = min_range >> AWS_LOG_SUBJECT_STRIDE_BITS;
     406           0 : 
     407           0 :     if (slot_index >= AWS_PACKAGE_SLOTS) {
     408           0 :         /* This is an NDEBUG build apparently. Kill the process rather than
     409           0 :          * corrupting heap. */
     410           0 :         fprintf(stderr, "Bad log subject slot index 0x%016x\n", slot_index);
     411           0 :         AWS_FATAL_ASSERT(false);
     412           0 :     }
     413           0 : 
     414           0 :     s_log_subject_slots[slot_index] = NULL;
     415           0 : }
     416             : 
     417             : /*
     418             :  * no alloc implementation
     419             :  */
     420             : struct aws_logger_noalloc {
     421             :     struct aws_atomic_var level;
     422             :     FILE *file;
     423             :     bool should_close;
     424             :     struct aws_mutex lock;
     425             : };
     426             : 
     427           0 : static enum aws_log_level s_noalloc_stderr_logger_get_log_level(struct aws_logger *logger, aws_log_subject_t subject) {
     428           0 :     (void)subject;
     429           0 : 
     430           0 :     struct aws_logger_noalloc *impl = logger->p_impl;
     431           0 :     return (enum aws_log_level)aws_atomic_load_int(&impl->level);
     432           0 : }
     433             : 
     434           0 : #define MAXIMUM_NO_ALLOC_LOG_LINE_SIZE 8192
     435             : 
     436             : static int s_noalloc_stderr_logger_log(
     437             :     struct aws_logger *logger,
     438             :     enum aws_log_level log_level,
     439             :     aws_log_subject_t subject,
     440             :     const char *format,
     441           0 :     ...) {
     442           0 : 
     443           0 :     char format_buffer[MAXIMUM_NO_ALLOC_LOG_LINE_SIZE];
     444           0 : 
     445           0 :     va_list format_args;
     446           0 :     va_start(format_args, format);
     447           0 : 
     448             : #if _MSC_VER
     449             : #    pragma warning(push)
     450             : #    pragma warning(disable : 4221) /* allow struct member to reference format_buffer  */
     451             : #endif
     452             : 
     453           0 :     struct aws_logging_standard_formatting_data format_data = {
     454           0 :         .log_line_buffer = format_buffer,
     455           0 :         .total_length = MAXIMUM_NO_ALLOC_LOG_LINE_SIZE,
     456           0 :         .level = log_level,
     457           0 :         .subject_name = aws_log_subject_name(subject),
     458           0 :         .format = format,
     459           0 :         .date_format = AWS_DATE_FORMAT_ISO_8601,
     460           0 :         .allocator = logger->allocator,
     461           0 :         .amount_written = 0,
     462           0 :     };
     463           0 : 
     464             : #if _MSC_VER
     465             : #    pragma warning(pop) /* disallow struct member to reference local value */
     466             : #endif
     467             : 
     468           0 :     int result = aws_format_standard_log_line(&format_data, format_args);
     469           0 : 
     470           0 :     va_end(format_args);
     471           0 : 
     472           0 :     if (result == AWS_OP_ERR) {
     473           0 :         return AWS_OP_ERR;
     474           0 :     }
     475           0 : 
     476           0 :     struct aws_logger_noalloc *impl = logger->p_impl;
     477           0 : 
     478           0 :     aws_mutex_lock(&impl->lock);
     479           0 : 
     480           0 :     if (fwrite(format_buffer, 1, format_data.amount_written, impl->file) < format_data.amount_written) {
     481           0 :         return aws_translate_and_raise_io_error(errno);
     482           0 :     }
     483           0 : 
     484           0 :     aws_mutex_unlock(&impl->lock);
     485           0 : 
     486           0 :     return AWS_OP_SUCCESS;
     487           0 : }
     488             : 
     489           0 : static void s_noalloc_stderr_logger_clean_up(struct aws_logger *logger) {
     490           0 :     if (logger == NULL) {
     491           0 :         return;
     492           0 :     }
     493           0 : 
     494           0 :     struct aws_logger_noalloc *impl = logger->p_impl;
     495           0 :     if (impl->should_close) {
     496           0 :         fclose(impl->file);
     497           0 :     }
     498           0 : 
     499           0 :     aws_mutex_clean_up(&impl->lock);
     500           0 : 
     501           0 :     aws_mem_release(logger->allocator, impl);
     502           0 :     AWS_ZERO_STRUCT(*logger);
     503           0 : }
     504             : 
     505           0 : int s_no_alloc_stderr_logger_set_log_level(struct aws_logger *logger, enum aws_log_level level) {
     506           0 :     struct aws_logger_noalloc *impl = logger->p_impl;
     507           0 : 
     508           0 :     aws_atomic_store_int(&impl->level, (size_t)level);
     509           0 : 
     510           0 :     return AWS_OP_SUCCESS;
     511           0 : }
     512             : 
     513             : static struct aws_logger_vtable s_noalloc_stderr_vtable = {
     514             :     .get_log_level = s_noalloc_stderr_logger_get_log_level,
     515             :     .log = s_noalloc_stderr_logger_log,
     516             :     .clean_up = s_noalloc_stderr_logger_clean_up,
     517             :     .set_log_level = s_no_alloc_stderr_logger_set_log_level,
     518             : };
     519             : 
     520             : int aws_logger_init_noalloc(
     521             :     struct aws_logger *logger,
     522             :     struct aws_allocator *allocator,
     523           0 :     struct aws_logger_standard_options *options) {
     524           0 : 
     525           0 :     struct aws_logger_noalloc *impl = aws_mem_calloc(allocator, 1, sizeof(struct aws_logger_noalloc));
     526           0 : 
     527           0 :     if (impl == NULL) {
     528           0 :         return AWS_OP_ERR;
     529           0 :     }
     530           0 : 
     531           0 :     aws_atomic_store_int(&impl->level, (size_t)options->level);
     532           0 : 
     533           0 :     if (options->file != NULL) {
     534           0 :         impl->file = options->file;
     535           0 :         impl->should_close = false;
     536           0 :     } else { /* _MSC_VER */
     537           0 :         impl->file = fopen(options->filename, "w");
     538           0 :         impl->should_close = true;
     539           0 :     }
     540           0 : 
     541           0 :     aws_mutex_init(&impl->lock);
     542           0 : 
     543           0 :     logger->vtable = &s_noalloc_stderr_vtable;
     544           0 :     logger->allocator = allocator;
     545           0 :     logger->p_impl = impl;
     546           0 : 
     547           0 :     return AWS_OP_SUCCESS;
     548           0 : }
     549             : 
     550           0 : int aws_logger_set_log_level(struct aws_logger *logger, enum aws_log_level level) {
     551           0 :     if (logger == NULL || logger->vtable == NULL) {
     552           0 :         return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
     553           0 :     }
     554           0 : 
     555           0 :     if (logger->vtable->set_log_level == NULL) {
     556           0 :         return aws_raise_error(AWS_ERROR_UNIMPLEMENTED);
     557           0 :     }
     558           0 : 
     559           0 :     return logger->vtable->set_log_level(logger, level);
     560           0 : }

Generated by: LCOV version 1.13