| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <lib/fdio/directory.h> |
| #include <lib/fdio/fd.h> |
| #include <lib/fdio/fdio.h> |
| #include <lib/log/log.h> |
| #include <lib/log/log_writer.h> |
| #include <stdio.h> |
| |
| #include <algorithm> |
| #include <memory> |
| |
| #include <fbl/algorithm.h> |
| #include <fbl/string.h> |
| #include <fbl/vector.h> |
| |
| namespace { |
| |
| // Configuration for a logger object. |
| // Specifies the destination to which log messages should be written. |
| typedef struct log_config { |
| // The minimum log level. |
| // Log messages with lower severity will be discarded. |
| // If this number is negative, it refers to a verbosity. |
| log_level_t min_level; |
| |
| // The writer that logs will go to. |
| log_writer_t* log_writer; |
| |
| // An array of tag strings to associate with all messages written |
| // by this logger. Tags will be truncated if they are (individually) longer |
| // than |LOG_MAX_TAG_LEN|. |
| fbl::Vector<fbl::String> tags; |
| } log_config_t; |
| |
| std::unique_ptr<log_config_t> g_log_config_ptr = std::unique_ptr<log_config_t>(nullptr); |
| |
| void log_write_message_helper(log_level_t level, size_t num_tags, const char** tags_ptr, |
| const char* message, size_t message_len) { |
| log_config_t* cfg = g_log_config_ptr.get(); |
| if (!cfg) { |
| // Logging has not been initialized. Don't log anything. |
| return; |
| } |
| |
| fbl::Vector<const char*> static_tags; |
| for (size_t i = 0; i < cfg->tags.size(); i++) { |
| static_tags.push_back(cfg->tags[i].c_str()); |
| } |
| |
| log_message_t msg = { |
| level, |
| static_tags.data(), |
| static_tags.size(), |
| tags_ptr, |
| num_tags, |
| message, |
| std::min(message_len, (size_t)LOG_MAX_MESSAGE_SIZE), |
| }; |
| cfg->log_writer->ops->v1.write(cfg->log_writer, &msg); |
| } |
| |
| } // namespace |
| |
| __EXPORT |
| bool log_level_is_enabled(log_level_t level) { |
| log_config_t* cfg = g_log_config_ptr.get(); |
| return cfg && level >= cfg->min_level; |
| } |
| |
| __EXPORT |
| void log_set_min_level(log_level_t level) { |
| log_config_t* cfg = g_log_config_ptr.get(); |
| if (cfg) { |
| cfg->min_level = level; |
| } |
| } |
| |
| __EXPORT |
| void log_initialize(log_level_t min_level, log_writer_t* log_writer, const size_t num_tags, |
| const char** tags) { |
| if (g_log_config_ptr.get() != nullptr) { |
| log_shutdown(); |
| } |
| log_config_t* config = new log_config_t; |
| config->min_level = min_level; |
| config->log_writer = log_writer; |
| |
| ZX_ASSERT(num_tags <= LOG_MAX_TAGS); |
| |
| for (size_t i = 0; i < num_tags; i++) { |
| config->tags.push_back(fbl::String(tags[i])); |
| } |
| |
| g_log_config_ptr = std::unique_ptr<log_config_t>(config); |
| } |
| |
| __EXPORT |
| void log_shutdown(void) { g_log_config_ptr = std::unique_ptr<log_config_t>(nullptr); } |
| |
| __EXPORT |
| void log_write_message_printf(log_level_t level, size_t num_tags, const char** tags_ptr, |
| const char* format_string, ...) { |
| char message[LOG_MAX_MESSAGE_SIZE]; |
| va_list args; |
| va_start(args, format_string); |
| int msg_len = vsnprintf(message, LOG_MAX_MESSAGE_SIZE, format_string, args); |
| va_end(args); |
| if (msg_len < 0) { |
| // There was an error formatting. Toss the message. |
| return; |
| } |
| log_write_message_helper(level, num_tags, tags_ptr, message, msg_len); |
| } |
| |
| __EXPORT |
| void log_write_message(log_level_t level, size_t num_tags, const char** tags_ptr, |
| const char* message) { |
| size_t message_len = strlen(message); |
| log_write_message_helper(level, num_tags, tags_ptr, message, message_len); |
| } |