diff --git a/.github/workflows/coverity_scan.yml b/.github/workflows/coverity_scan.yml new file mode 100644 index 00000000..3b5b1964 --- /dev/null +++ b/.github/workflows/coverity_scan.yml @@ -0,0 +1,51 @@ +name: coverity-linux + +on: [pull_request] + +permissions: + contents: read + +jobs: + coverity_scan: + runs-on: ubuntu-latest + name: Coverity Scan + steps: + - uses: actions/checkout@v4 + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y curl build-essential cmake pkg-config libsystemd-dev + + - name: Download Coverity Tool + run: | + curl -s -L --output coverity_tool.tgz "https://scan.coverity.com/download/linux64?token=${{ secrets.COVERITY_TOKEN }}&project=gabime%2Fspdlog" + mkdir coverity_tool + tar -C coverity_tool --strip-components=1 -xf coverity_tool.tgz + echo "$PWD/coverity_tool/bin" >> $GITHUB_PATH + + - name: Build with Coverity + run: | + mkdir build && cd build + cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_STANDARD=17 + cd .. + cov-build --dir cov-int make -C build -j4 + + - name: Submit results to Coverity + run: | + tar czf cov-int.tgz cov-int + response=$(curl --silent --show-error --fail \ + --form token="${{ secrets.COVERITY_TOKEN }}" \ + --form file=@cov-int.tgz \ + --form version="GitHub PR #${{ github.event.pull_request.number }}" \ + --form description="CI run for PR" \ + https://scan.coverity.com/builds?project=gabime%2Fspdlog) + + echo "$response" + + if echo "$response" | grep -qi "Build successfully submitted"; then + echo "Coverity upload succeeded" + else + echo "Coverity upload failed or was rejected" + exit 1 + fi diff --git a/example/example.cpp b/example/example.cpp index 3925fb81..16575d19 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -33,41 +33,41 @@ void mdc_example(); #include "spdlog/fmt/ostr.h" // support for user defined types int main(int, char *[]) { - // Log levels can be loaded from argv/env using "SPDLOG_LEVEL" - load_levels_example(); - - spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, - SPDLOG_VER_PATCH); - - spdlog::warn("Easy padding in numbers like {:08d}", 12); - spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); - spdlog::info("Support for floats {:03.2f}", 1.23456); - spdlog::info("Positional args are {1} {0}..", "too", "supported"); - spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left"); - - // Runtime log levels - spdlog::set_level(spdlog::level::info); // Set global log level to info - spdlog::debug("This message should not be displayed!"); - spdlog::set_level(spdlog::level::trace); // Set specific logger's log level - spdlog::debug("This message should be displayed.."); - - // Customize msg format for all loggers - spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v"); - spdlog::info("This an info message with custom format"); - spdlog::set_pattern("%+"); // back to default format - spdlog::set_level(spdlog::level::info); - - // Backtrace support - // Loggers can store in a ring buffer all messages (including debug/trace) for later inspection. - // When needed, call dump_backtrace() to see what happened: - spdlog::enable_backtrace(10); // create ring buffer with capacity of 10 messages - for (int i = 0; i < 100; i++) { - spdlog::debug("Backtrace message {}", i); // not logged.. - } - // e.g. if some error happened: - spdlog::dump_backtrace(); // log them now! - try { + // Log levels can be loaded from argv/env using "SPDLOG_LEVEL" + load_levels_example(); + + spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, + SPDLOG_VER_PATCH); + + spdlog::warn("Easy padding in numbers like {:08d}", 12); + spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); + spdlog::info("Support for floats {:03.2f}", 1.23456); + spdlog::info("Positional args are {1} {0}..", "too", "supported"); + spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left"); + + // Runtime log levels + spdlog::set_level(spdlog::level::info); // Set global log level to info + spdlog::debug("This message should not be displayed!"); + spdlog::set_level(spdlog::level::trace); // Set specific logger's log level + spdlog::debug("This message should be displayed.."); + + // Customize msg format for all loggers + spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v"); + spdlog::info("This an info message with custom format"); + spdlog::set_pattern("%+"); // back to default format + spdlog::set_level(spdlog::level::info); + + // Backtrace support + // Loggers can store in a ring buffer all messages (including debug/trace) for later + // inspection. When needed, call dump_backtrace() to see what happened: + spdlog::enable_backtrace(10); // create ring buffer with capacity of 10 messages + for (int i = 0; i < 100; i++) { + spdlog::debug("Backtrace message {}", i); // not logged.. + } + // e.g. if some error happened: + spdlog::dump_backtrace(); // log them now! + stdout_logger_example(); basic_example(); rotating_example(); @@ -371,15 +371,13 @@ void replace_default_logger_example() { // store the old logger so we don't break other examples. auto old_logger = spdlog::default_logger(); - auto new_logger = - spdlog::basic_logger_mt("new_default_logger", "logs/new-default-log.txt", true); - spdlog::set_default_logger(new_logger); + auto new_logger = spdlog::basic_logger_mt("new_default_logger", "logs/somelog.txt", true); + spdlog::set_default_logger(std::move(new_logger)); spdlog::set_level(spdlog::level::info); spdlog::debug("This message should not be displayed!"); spdlog::set_level(spdlog::level::trace); spdlog::debug("This message should be displayed.."); - - spdlog::set_default_logger(old_logger); + spdlog::set_default_logger(std::move(old_logger)); } // Mapped Diagnostic Context (MDC) is a map that stores key-value pairs (string values) in thread diff --git a/include/spdlog/cfg/helpers-inl.h b/include/spdlog/cfg/helpers-inl.h index 93650a2e..1b2a5049 100644 --- a/include/spdlog/cfg/helpers-inl.h +++ b/include/spdlog/cfg/helpers-inl.h @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -36,7 +35,7 @@ inline std::string &trim_(std::string &str) { return str; } -// return (name,value) trimmed pair from given "name=value" string. +// return (name,value) trimmed pair from the given "name = value" string. // return empty string on missing parts // "key=val" => ("key", "val") // " key = val " => ("key", "val") @@ -55,7 +54,7 @@ inline std::pair extract_kv_(char sep, const std::stri return std::make_pair(trim_(k), trim_(v)); } -// return vector of key/value pairs from sequence of "K1=V1,K2=V2,.." +// return vector of key/value pairs from a sequence of "K1=V1,K2=V2,.." // "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...} inline std::unordered_map extract_key_vals_(const std::string &str) { std::string token; @@ -82,14 +81,14 @@ SPDLOG_INLINE void load_levels(const std::string &input) { bool global_level_found = false; for (auto &name_level : key_vals) { - auto &logger_name = name_level.first; - auto level_name = to_lower_(name_level.second); + const auto &logger_name = name_level.first; + const auto &level_name = to_lower_(name_level.second); auto level = level::from_str(level_name); // ignore unrecognized level names if (level == level::off && level_name != "off") { continue; } - if (logger_name.empty()) // no logger name indicate global level + if (logger_name.empty()) // no logger name indicates global level { global_level_found = true; global_level = level; diff --git a/include/spdlog/details/file_helper-inl.h b/include/spdlog/details/file_helper-inl.h index 8742b96c..0c514ef2 100644 --- a/include/spdlog/details/file_helper-inl.h +++ b/include/spdlog/details/file_helper-inl.h @@ -11,10 +11,8 @@ #include #include -#include #include #include -#include #include namespace spdlog { diff --git a/include/spdlog/details/registry-inl.h b/include/spdlog/details/registry-inl.h index 4cbdeb75..272bebbd 100644 --- a/include/spdlog/details/registry-inl.h +++ b/include/spdlog/details/registry-inl.h @@ -101,7 +101,7 @@ SPDLOG_INLINE std::shared_ptr registry::default_logger() { SPDLOG_INLINE logger *registry::get_default_raw() { return default_logger_.get(); } // set default logger. -// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. +// the default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr new_default_logger) { std::lock_guard lock(logger_map_mutex_); if (new_default_logger != nullptr) { diff --git a/include/spdlog/details/thread_pool-inl.h b/include/spdlog/details/thread_pool-inl.h index 68b55369..b172b280 100644 --- a/include/spdlog/details/thread_pool-inl.h +++ b/include/spdlog/details/thread_pool-inl.h @@ -35,7 +35,7 @@ SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function on_thread_start) - : thread_pool(q_max_items, threads_n, on_thread_start, [] {}) {} + : thread_pool(q_max_items, threads_n, std::move(on_thread_start), [] {}) {} SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n) : thread_pool(q_max_items, threads_n, [] {}, [] {}) {} @@ -94,8 +94,7 @@ void SPDLOG_INLINE thread_pool::worker_loop_() { } // process next message in the queue -// return true if this thread should still be active (while no terminate msg -// was received) +// returns true if this thread should still be active (while no terminated msg was received) bool SPDLOG_INLINE thread_pool::process_next_msg_() { async_msg incoming_async_msg; q_.dequeue(incoming_async_msg); diff --git a/include/spdlog/logger-inl.h b/include/spdlog/logger-inl.h index 5218fe4c..6879273c 100644 --- a/include/spdlog/logger-inl.h +++ b/include/spdlog/logger-inl.h @@ -57,7 +57,7 @@ SPDLOG_INLINE void logger::swap(spdlog::logger &other) SPDLOG_NOEXCEPT { std::swap(tracer_, other.tracer_); } -SPDLOG_INLINE void swap(logger &a, logger &b) { a.swap(b); } +SPDLOG_INLINE void swap(logger &a, logger &b) noexcept { a.swap(b); } SPDLOG_INLINE void logger::set_level(level::level_enum log_level) { level_.store(log_level); } @@ -163,12 +163,12 @@ SPDLOG_INLINE void logger::dump_backtrace_() { } } -SPDLOG_INLINE bool logger::should_flush_(const details::log_msg &msg) { +SPDLOG_INLINE bool logger::should_flush_(const details::log_msg &msg) const { auto flush_level = flush_level_.load(std::memory_order_relaxed); return (msg.level >= flush_level) && (msg.level != level::off); } -SPDLOG_INLINE void logger::err_handler_(const std::string &msg) { +SPDLOG_INLINE void logger::err_handler_(const std::string &msg) const { if (custom_err_handler_) { custom_err_handler_(msg); } else { diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index f49bdc00..8c3cd91f 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -363,14 +363,14 @@ protected: virtual void sink_it_(const details::log_msg &msg); virtual void flush_(); void dump_backtrace_(); - bool should_flush_(const details::log_msg &msg); + bool should_flush_(const details::log_msg &msg) const; // handle errors during logging. // default handler prints the error to stderr at max rate of 1 message/sec. - void err_handler_(const std::string &msg); + void err_handler_(const std::string &msg) const; }; -void swap(logger &a, logger &b); +void swap(logger &a, logger &b) noexcept; } // namespace spdlog