diff --git a/.clang-format b/.clang-format index 05f6728..c1d497d 100644 --- a/.clang-format +++ b/.clang-format @@ -6,13 +6,22 @@ # BasedOnStyle: Google +BreakStringLiterals: true NamespaceIndentation: All BreakBeforeBinaryOperators: NonAssignment -AlignOperands: false +AlignOperands: AlignAfterOperator DerivePointerAlignment: false PointerAlignment: Right -BinPackArguments: true -BinPackParameters: true +BinPackArguments: false +BinPackParameters: false AllowShortFunctionsOnASingleLine: Empty -AllowShortIfStatementsOnASingleLine: false IncludeBlocks: Preserve +InsertBraces: true +InsertTrailingCommas: Wrapped +SortIncludes: CaseSensitive +QualifierAlignment: Custom +QualifierOrder: ['inline', 'static', 'constexpr', 'const', 'volatile', 'type', 'restrict'] +ReferenceAlignment: Right +ReflowComments: true +#RemoveSemicolon: true +InsertNewlineAtEOF: true diff --git a/.clang-tidy b/.clang-tidy index feefcd9..60e8448 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -6,9 +6,50 @@ # --- -Checks: '-*,clang-analyzer-*,clang-diagnostic-*,readability-*,modernize-*,-modernize-use-trailing-return-type,boost-*,bugprone-*,cppcoreguidelines-*,google-*,hicpp-*,performance-*,readability-*,-google-readability-namespace-comments,-readability-inconsistent-declaration-parameter-name,-readability-braces-around-statements,-hicpp-signed-bitwise,-google-runtime-references,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-readability-magic-numbers,-hicpp-explicit-conversions,-hicpp-uppercase-literal-suffix,-readability-uppercase-literal-suffix,-hicpp-no-array-decay,-hicpp-special-member-functions,-bugprone-narrowing-conversions,-modernize-use-nodiscard,-google-readability-braces-around-statements,-hicpp-braces-around-statements,-bugprone-suspicious-semicolon,-readability-named-parameter,-hicpp-named-parameter,-readability-identifier-naming' -WarningsAsErrors: 'modernize-*,cppcoreguidelines-*,boost-*,google-build-using-namespace,readability-else-after-return,google-readability-todo' -AnalyzeTemporaryDtors: false +Checks: "-*, + clang-analyzer-*, \ + clang-diagnostic-*, \ + -clang-diagnostic-missing-template-arg-list-after-template-kw, \ + modernize-*, \ + -modernize-use-nodiscard, \ + -modernize-use-trailing-return-type, \ + boost-*, \ + bugprone-*, \ + -bugprone-narrowing-conversions, \ + -bugprone-suspicious-semicolon, \ + cppcoreguidelines-*, \ + -cppcoreguidelines-rvalue-reference-param-not-moved, \ + -cppcoreguidelines-avoid-magic-numbers, \ + -cppcoreguidelines-pro-bounds-array-to-pointer-decay, \ + google-*, \ + -google-readability-namespace-comments, \ + -google-readability-braces-around-statements, \ + -google-runtime-references, \ + hicpp-*, \ + -hicpp-explicit-conversions, \ + -hicpp-uppercase-literal-suffix, \ + -hicpp-signed-bitwise, \ + -hicpp-no-array-decay, \ + -hicpp-special-member-functions, \ + -hicpp-braces-around-statements, \ + -hicpp-named-parameter, \ + performance-*, \ + readability-*, \ + -readability-magic-numbers, \ + -readability-named-parameter, \ + -readability-identifier-naming, \ + -readability-uppercase-literal-suffix, \ + -readability-inconsistent-declaration-parameter-name, \ + -readability-braces-around-statements" +WarningsAsErrors: "modernize-*, \ + cppcoreguidelines-*, \ + boost-*, \ + performance-*, \ + google-build-using-namespace, \ + readability-else-after-return, \ + readability-container-contains, \ + google-readability-todo" +HeaderFilterRegex: '\(hpp|h|pb\.h)' FormatStyle: .clang-format User: user CheckOptions: diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 353d2b6..176cc35 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -15,12 +15,12 @@ fi # check clang-format binary CLANG_FORMAT_ENABLED=1 -CLANG_FORMAT=$(which clang-format-15) +CLANG_FORMAT=$(which clang-format-19) if [ -z "${CLANG_FORMAT}" ]; then CLANG_FORMAT=$(which clang-format) if [ -z "${CLANG_FORMAT}" ]; then echo "Command clang-format is not found" >&2 - echo "Please, install clang-format version 15 to enable checkup C++-files formatting over git pre-commit hook" >&2 + echo "Please, install clang-format version 19 to enable checkup C++-files formatting over git pre-commit hook" >&2 CLANG_FORMAT_ENABLED=0 fi fi @@ -29,8 +29,8 @@ fi if [ $CLANG_FORMAT_ENABLED ]; then CLANG_FORMAT_VERSION=$($CLANG_FORMAT --version | sed -r "s/.*version ([[:digit:]]+).*/\1/") - if [ "$CLANG_FORMAT_VERSION" != "15" ]; then - echo "Please, install clang-format version 15 to enable checkup C++-files formatting over git pre-commit hook" >&2 + if [ "$CLANG_FORMAT_VERSION" != "19" ]; then + echo "Please, install clang-format version 19 to enable checkup C++-files formatting over git pre-commit hook" >&2 CLANG_FORMAT_ENABLED=0 fi fi diff --git a/.github/workflows/clang-tidy.yml b/.github/workflows/clang-tidy.yml index f330540..5fd86c7 100644 --- a/.github/workflows/clang-tidy.yml +++ b/.github/workflows/clang-tidy.yml @@ -17,7 +17,7 @@ on: jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v1 name: checkout @@ -29,20 +29,20 @@ jobs: run: | set -e sudo apt-get update || true - sudo apt-get install -y ninja-build gcovr gcc-13 g++-13 clang-15 clang++-15 llvm-15 + sudo apt-get install -y ninja-build gcovr gcc-13 g++-13 llvm-18 clang-18 clang++-18 clang-tidy-18 clang-format-18 sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 90 - sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-15 999 - sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 999 - sudo update-alternatives --install /usr/bin/clang clang /usr/lib/llvm-15/bin/clang-15 999 - sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-15 999 + sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-18 999 + sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-18 999 + sudo update-alternatives --install /usr/bin/clang clang /usr/lib/llvm-18/bin/clang-18 999 + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 999 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 90 sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 90 sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-13 90 - sudo python3 -m pip install --upgrade pip - sudo python3 -m pip install scikit-build - sudo python3 -m pip install cmake==3.25 requests gitpython gcovr pyyaml +# sudo python3 -m pip install --upgrade pip +# sudo python3 -m pip install scikit-build +# sudo python3 -m pip install cmake==3.25 requests gitpython gcovr pyyaml - name: run checks run: | #!/bin/bash diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index a368d45..17fd9c7 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, macOS-14] + os: [ubuntu-24.04, macos-15] compiler: [{ "cc": "gcc", "cxx": "g++" @@ -30,7 +30,7 @@ jobs: "cxx": "clang++" }] exclude: - - os: macOS-14 + - os: macos-15 compiler: cc: gcc steps: @@ -52,12 +52,13 @@ jobs: brew install ninja else sudo apt-get update || true - sudo apt-get install -y ninja-build gcc-13 g++-13 clang-15 clang++-15 + sudo apt-get install -y ninja-build gcovr gcc-13 g++-13 clang-18 clang++-18 clang-tidy-18 clang-format-18 + sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 90 - sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-15 999 - sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 999 - sudo update-alternatives --install /usr/bin/clang clang /usr/lib/llvm-15/bin/clang-15 999 - sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-15 999 + sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-18 999 + sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-18 999 + sudo update-alternatives --install /usr/bin/clang clang /usr/lib/llvm-18/bin/clang-18 999 + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 999 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 90 sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 90 sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-13 90 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index f813a76..fb3664f 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -18,7 +18,7 @@ on: jobs: coverage: name: "codecov" - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: checkout uses: actions/checkout@v1 @@ -30,20 +30,20 @@ jobs: run: | set -e sudo apt-get update || true - sudo apt-get install -y ninja-build gcovr gcc-13 g++-13 clang-15 clang++-15 + sudo apt-get install -y ninja-build gcovr gcc-13 g++-13 clang-18 clang++-18 clang-tidy-18 clang-format-18 sudo update-alternatives --install /usr/bin/python python /usr/bin/python3 90 - sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-15 999 - sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 999 - sudo update-alternatives --install /usr/bin/clang clang /usr/lib/llvm-15/bin/clang-15 999 - sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-15 999 + sudo update-alternatives --install /usr/bin/clang-tidy clang-tidy /usr/bin/clang-tidy-18 999 + sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-18 999 + sudo update-alternatives --install /usr/bin/clang clang /usr/lib/llvm-18/bin/clang-18 999 + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 999 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 90 sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 90 sudo update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-13 90 - sudo python3 -m pip install --upgrade pip - sudo python3 -m pip install scikit-build - sudo python3 -m pip install cmake==3.25 requests gitpython gcovr pyyaml +# sudo python3 -m pip install --upgrade pip +# sudo python3 -m pip install scikit-build +# sudo python3 -m pip install cmake==3.25 requests gitpython gcovr pyyaml - name: "cmake" env: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 503309f..12d6417 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,7 +38,7 @@ jobs: - name: "Undefined Behavior Sanitizer" sanitizer: UBSAN name: "${{ matrix.options.name }}" - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: checkout uses: actions/checkout@v1 @@ -52,8 +52,8 @@ jobs: set -e sudo apt-get update || true sudo apt-get install -y ninja-build - sudo python3 -m pip install --upgrade pip - sudo pip3 install cmake requests gitpython gcovr pyyaml +# sudo python3 -m pip install --upgrade pip +# sudo pip3 install cmake requests gitpython gcovr pyyaml - name: cmake env: diff --git a/example/01-simple/logger.yml b/example/01-simple/logger.yml index 18a2735..e546493 100644 --- a/example/01-simple/logger.yml +++ b/example/01-simple/logger.yml @@ -5,64 +5,53 @@ # SPDX-License-Identifier: Apache-2.0 # -sinks: - - name: colored_stdout - type: console - stream: stdout - color: true - thread: name - capacity: 64 - max_message_length: 120 - buffer: 131072 - latency: 100 - - name: simple_stderr - type: console - stream: stderr - color: false - thread: name - capacity: 64 - max_message_length: 120 - buffer: 131072 - latency: 100 - - name: file - type: file - path: /tmp/solalog_example.log - thread: name - capacity: 2048 - buffer: 4194304 - latency: 1000 - - name: syslog - type: syslog - ident: solalog_example - thread: name - capacity: 2048 - buffer: 4194304 - latency: 1000 - - name: sink_to_everywhere - type: multisink - sinks: +sinks: # List of sink configurations + - name: colored_stdout # Unique name of the sink + type: console # Sink type: 'console' means output to the standard output or error stream + stream: stdout # Output stream type (stdout or stderr) + color: true # Whether to insert escape sequences for colored output + thread: name # Thread differentiation method: 'name' for named threads, 'id' for enumerated threads, 'none' for no print (default) + capacity: 64 # Maximum number of buffered messages; affects memory usage + max_message_length: 120 # Maximum length of a single message; extra characters are dropped, affects memory usage + buffer: 131072 # Maximum buffered data size in bytes before forcing a flush + latency: 100 # Maximum delay in milliseconds before forcing a buffer flush; 0 means immediate flushing (default) + level: trace # Maximum log level this sink accepts (from trace and above) + - name: simple_stderr # Unique name of the sink + type: console # Sink type: 'console' means output to the standard output or error stream + stream: stderr # Output stream type (stdout or stderr) + color: false # Whether to insert escape sequences for colored output + thread: name # Thread differentiation method: 'name' for named threads, 'id' for enumerated threads, 'none' for no print (default) + capacity: 64 # Maximum number of buffered messages; affects memory usage + max_message_length: 120 # Maximum length of a single message; extra characters are dropped, affects memory usage + buffer: 131072 # Maximum buffered data size in bytes before forcing a flush + latency: 100 # Maximum delay in milliseconds before forcing a buffer flush + level: info # Maximum log level this sink accepts (from info and above) + - name: file # Unique name of the sink + type: file # Sink type: 'file' means output to a file + path: /tmp/solalog_example.log # Path to the output file + thread: name # Thread differentiation method: 'name' for named threads, 'id' for enumerated threads, 'none' for no print (default) + capacity: 2048 # Maximum number of buffered messages; affects memory usage + buffer: 4194304 # Maximum buffered data size in bytes before forcing a flush + latency: 1000 # Maximum delay in milliseconds before forcing a buffer flush; 0 means immediate flushing (default) + - name: syslog # Unique name of the sink + type: syslog # Sink type: 'syslog' means messages are sent to the system's syslog daemon + ident: solalog_example # Identifier for the syslog channel + thread: name # Thread differentiation method: 'name' for named threads, 'id' for enumerated threads, 'none' for no print (default) + capacity: 2048 # Maximum number of buffered messages; affects memory usage + buffer: 4194304 # Maximum buffered data size in bytes before forcing a flush + latency: 1000 # Maximum delay in milliseconds before forcing a buffer flush; 0 means immediate flushing (default) + - name: sink_to_everywhere # Unique name of the sink + type: multisink # Sink type: 'multisink' means messages are broadcasted to the specified underlying sinks + sinks: # List of underlying sinks by name - file - colored_stdout - simple_stderr - syslog -groups: - - name: main - sink: sink_to_everywhere - level: trace - children: - - name: blockchain - - name: consensus - level: debug - children: - - name: grandpa - level: info - - name: babe - children: - - name: block_executor - level: trace - - name: runtime - level: off - children: - - name: transaction - sink: file - level: debug +groups: # List of group configurations + - name: main # Unique name of the group + sink: sink_to_everywhere # Name of the sink used for output from loggers in this group; must be defined for a root group + level: trace # Maximum log level this group accepts; must be defined for a root group + is_fallback: true # If true, this group is the default fallback group; only one group can be marked as fallback + children: # Nested groups; these groups inherit properties from the parent + - name: example_group + - name: another_group diff --git a/example/01-simple/main.cpp b/example/01-simple/main.cpp index 5a08a81..427f7cd 100644 --- a/example/01-simple/main.cpp +++ b/example/01-simple/main.cpp @@ -12,7 +12,9 @@ #include "logging_object.hpp" -enum ConfiguratorType { +using std::literals::string_literals::operator""s; + +enum class ConfiguratorType : uint8_t { Fallback, Customized, YamlByPath, @@ -107,7 +109,7 @@ int main() { auto r = log_system.configure(); if (not r.message.empty()) { - (r.has_error ? std::cerr : std::cout) << r.message << std::endl; + (r.has_error ? std::cerr : std::cout) << r.message << '\n'; } if (r.has_error) { exit(EXIT_FAILURE); @@ -123,7 +125,7 @@ int main() { main_log->info("Start"); auto lambda = [](const auto &tag) { - std::cout << "CALCULATED: " << tag << std::endl; + std::cout << "CALCULATED: " << tag << '\n'; return tag; }; @@ -156,14 +158,16 @@ int main() { "Very long message |.....30->|.....40->|.....50->|.....60->|.....70->|" ".....80->|.....90->|....100->|....110->|....120->|....130->|....140->|"); - auto dynamic_format = std::string("Custom made format: {} ==>") + "<== {}"; + auto dynamic_format = "Custom made format: {} ==>"s + "<== {}"s; main_log->info(dynamic_format, 1, 2); SL_INFO_DF(main_log, dynamic_format, 3, 4); LoggingObject object(log_system); object.method(); - for (auto &thread : threads) thread->join(); + for (auto &thread : threads) { + thread->join(); + } main_log->info("Finish"); diff --git a/include/soralog/circular_buffer.hpp b/include/soralog/circular_buffer.hpp index 7ed69e5..25d8510 100644 --- a/include/soralog/circular_buffer.hpp +++ b/include/soralog/circular_buffer.hpp @@ -53,7 +53,7 @@ namespace soralog { NodeRef(NodeRef &&) noexcept = delete; NodeRef(const NodeRef &) = delete; NodeRef &operator=(NodeRef &&) noexcept = delete; - NodeRef &operator=(NodeRef const &) = delete; + NodeRef &operator=(const NodeRef &) = delete; NodeRef(Node &node) noexcept : node(&node) {} @@ -83,7 +83,7 @@ namespace soralog { CircularBuffer(const CircularBuffer &) = delete; ~CircularBuffer() = default; CircularBuffer &operator=(CircularBuffer &&) noexcept = delete; - CircularBuffer &operator=(CircularBuffer const &) = delete; + CircularBuffer &operator=(const CircularBuffer &) = delete; CircularBuffer(size_t capacity, size_t padding) : capacity_(capacity), @@ -102,7 +102,7 @@ namespace soralog { }; // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,hicpp-member-init) - explicit CircularBuffer(size_t capacity) : CircularBuffer(capacity, 0){}; + explicit CircularBuffer(size_t capacity) : CircularBuffer(capacity, 0) {}; size_t capacity() const noexcept { while (busy_.test_and_set()) { diff --git a/include/soralog/event.hpp b/include/soralog/event.hpp index 7417c28..a673b0d 100644 --- a/include/soralog/event.hpp +++ b/include/soralog/event.hpp @@ -34,7 +34,7 @@ namespace soralog { Event(const Event &) = delete; ~Event() = default; Event &operator=(Event &&) noexcept = delete; - Event &operator=(Event const &) = delete; + Event &operator=(const Event &) = delete; /** * @param name of logger @@ -43,8 +43,12 @@ namespace soralog { */ template // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,hicpp-member-init) - Event(std::string_view name, ThreadInfoType thread_info_type, Level level, - const Format &format, size_t max_message_length, const Args &...args) + Event(std::string_view name, + ThreadInfoType thread_info_type, + Level level, + const Format &format, + size_t max_message_length, + const Args &...args) : timestamp_(std::chrono::system_clock::now()), level_(level) { switch (thread_info_type) { case ThreadInfoType::NAME: @@ -86,14 +90,17 @@ namespace soralog { try { message_size_ = ::fmt::vformat_to_n( - it, max_message_length, + it, + max_message_length, ::fmt::detail_exported::compile_string_to_view(format), ::fmt::make_format_args(args...)) .size; } catch (const std::exception &exception) { - message_size_ = fmt::format_to_n(it, max_message_length, + message_size_ = fmt::format_to_n(it, + max_message_length, "Format error: {}; Format: {}", - exception.what(), format) + exception.what(), + format) .size; name = "Soralog"; level_ = Level::ERROR; diff --git a/include/soralog/group.hpp b/include/soralog/group.hpp index 4585ed6..f1511bd 100644 --- a/include/soralog/group.hpp +++ b/include/soralog/group.hpp @@ -28,9 +28,10 @@ namespace soralog { Group(const Group &) = delete; virtual ~Group() = default; Group &operator=(Group &&) noexcept = delete; - Group &operator=(Group const &) = delete; + Group &operator=(const Group &) = delete; - Group(LoggingSystem &logging_system, std::string group_name, + Group(LoggingSystem &logging_system, + std::string group_name, const std::optional &parent_name, const std::optional &sink_name, std::optional level); diff --git a/include/soralog/impl/configurator_from_yaml.hpp b/include/soralog/impl/configurator_from_yaml.hpp index b59d118..7ee1e2a 100644 --- a/include/soralog/impl/configurator_from_yaml.hpp +++ b/include/soralog/impl/configurator_from_yaml.hpp @@ -29,13 +29,13 @@ namespace soralog { * Uses YAML-file {@param config_path} as source of config */ explicit ConfiguratorFromYAML(std::filesystem::path config_path) - : config_(std::move(config_path)){}; + : config_(std::move(config_path)) {}; /** * Uses YAML-content {@param config_content} as source of config */ explicit ConfiguratorFromYAML(std::string config_content) - : config_(std::move(config_content)){}; + : config_(std::move(config_content)) {}; /** * Uses YAML-file {@param config_path} as source of config. @@ -43,7 +43,7 @@ namespace soralog { */ explicit ConfiguratorFromYAML(std::shared_ptr previous, std::filesystem::path config_path) - : previous_(std::move(previous)), config_(std::move(config_path)){}; + : previous_(std::move(previous)), config_(std::move(config_path)) {}; /** * Uses YAML-content {@param config_content} as source of config @@ -51,7 +51,7 @@ namespace soralog { */ explicit ConfiguratorFromYAML(std::shared_ptr previous, std::string config_content) - : previous_(std::move(previous)), config_(std::move(config_content)){}; + : previous_(std::move(previous)), config_(std::move(config_content)) {}; ~ConfiguratorFromYAML() override = default; @@ -78,6 +78,9 @@ namespace soralog { private: void parse(const YAML::Node &node); + std::optional parseLevel(const std::string &target, + const YAML::Node &node); + void parseSinks(const YAML::Node &sinks); void parseSink(int number, const YAML::Node &sink); @@ -96,9 +99,11 @@ namespace soralog { void parseGroups(const YAML::Node &groups, const std::optional &parent); - void parseGroup(int number, const YAML::Node &group_node, + void parseGroup(int number, + const YAML::Node &group_node, const std::optional &parent); + // NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members) LoggingSystem &system_; std::shared_ptr previous_ = nullptr; std::variant config_; diff --git a/include/soralog/impl/multisink.hpp b/include/soralog/impl/multisink.hpp index 54af64a..faca586 100644 --- a/include/soralog/impl/multisink.hpp +++ b/include/soralog/impl/multisink.hpp @@ -23,15 +23,17 @@ namespace soralog { Multisink(Multisink &&) noexcept = delete; Multisink(const Multisink &) = delete; Multisink &operator=(Multisink &&) noexcept = delete; - Multisink &operator=(Multisink const &) = delete; + Multisink &operator=(const Multisink &) = delete; - Multisink(std::string name, std::vector> sinks); + Multisink(std::string name, + Level level, + std::vector> sinks); void rotate() noexcept override; void flush() noexcept override; private: - void async_flush() noexcept override{}; + void async_flush() noexcept override {}; }; } // namespace soralog diff --git a/include/soralog/impl/sink_to_console.hpp b/include/soralog/impl/sink_to_console.hpp index f8ab384..62ea6e4 100644 --- a/include/soralog/impl/sink_to_console.hpp +++ b/include/soralog/impl/sink_to_console.hpp @@ -19,15 +19,21 @@ namespace soralog { class SinkToConsole final : public Sink { public: - enum class Stream { STDOUT = 1, STDERR = 2 }; + enum class Stream : uint8_t { + STDOUT = 1, + STDERR = 2, + }; SinkToConsole() = delete; SinkToConsole(SinkToConsole &&) noexcept = delete; SinkToConsole(const SinkToConsole &) = delete; SinkToConsole &operator=(SinkToConsole &&) noexcept = delete; - SinkToConsole &operator=(SinkToConsole const &) = delete; + SinkToConsole &operator=(const SinkToConsole &) = delete; - SinkToConsole(std::string name, Stream stream_type, bool with_color, + SinkToConsole(std::string name, + Level level, + Stream stream_type, + bool with_color, std::optional thread_info_type = {}, std::optional capacity = {}, std::optional max_message_length = {}, @@ -35,7 +41,7 @@ namespace soralog { std::optional latency = {}); ~SinkToConsole() override; - void rotate() noexcept override{}; + void rotate() noexcept override {}; void flush() noexcept override; diff --git a/include/soralog/impl/sink_to_file.hpp b/include/soralog/impl/sink_to_file.hpp index 08fd6e6..f61aa27 100644 --- a/include/soralog/impl/sink_to_file.hpp +++ b/include/soralog/impl/sink_to_file.hpp @@ -25,9 +25,11 @@ namespace soralog { SinkToFile(SinkToFile &&) noexcept = delete; SinkToFile(const SinkToFile &) = delete; SinkToFile &operator=(SinkToFile &&) noexcept = delete; - SinkToFile &operator=(SinkToFile const &) = delete; + SinkToFile &operator=(const SinkToFile &) = delete; - SinkToFile(std::string name, std::filesystem::path path, + SinkToFile(std::string name, + Level level, + std::filesystem::path path, std::optional thread_info_type = {}, std::optional capacity = {}, std::optional buffer_size = {}, diff --git a/include/soralog/impl/sink_to_nowhere.hpp b/include/soralog/impl/sink_to_nowhere.hpp index a001d5a..2b1a230 100644 --- a/include/soralog/impl/sink_to_nowhere.hpp +++ b/include/soralog/impl/sink_to_nowhere.hpp @@ -18,7 +18,7 @@ namespace soralog { SinkToNowhere(SinkToNowhere &&) noexcept = delete; SinkToNowhere(const SinkToNowhere &) = delete; SinkToNowhere &operator=(SinkToNowhere &&) noexcept = delete; - SinkToNowhere &operator=(SinkToNowhere const &) = delete; + SinkToNowhere &operator=(const SinkToNowhere &) = delete; explicit SinkToNowhere(std::string name); ~SinkToNowhere() override; diff --git a/include/soralog/impl/sink_to_syslog.hpp b/include/soralog/impl/sink_to_syslog.hpp index 2435752..40c1c84 100644 --- a/include/soralog/impl/sink_to_syslog.hpp +++ b/include/soralog/impl/sink_to_syslog.hpp @@ -23,9 +23,11 @@ namespace soralog { SinkToSyslog(SinkToSyslog &&) noexcept = delete; SinkToSyslog(const SinkToSyslog &) = delete; SinkToSyslog &operator=(SinkToSyslog &&) noexcept = delete; - SinkToSyslog &operator=(SinkToSyslog const &) = delete; + SinkToSyslog &operator=(const SinkToSyslog &) = delete; - SinkToSyslog(std::string name, std::string ident, + SinkToSyslog(std::string name, + Level level, + std::string ident, std::optional thread_info_type = {}, std::optional capacity = {}, std::optional max_message_length = {}, @@ -33,7 +35,7 @@ namespace soralog { std::optional latency = {}); ~SinkToSyslog() override; - void rotate() noexcept override{}; + void rotate() noexcept override {}; void flush() noexcept override; diff --git a/include/soralog/level.hpp b/include/soralog/level.hpp index d773952..f1331f3 100644 --- a/include/soralog/level.hpp +++ b/include/soralog/level.hpp @@ -43,7 +43,7 @@ namespace soralog { r[static_cast(Level::IGNORE)] = "?Ignore"; return r; }(); - } + } // namespace detail /** * @returns symbol in according with {@param level} diff --git a/include/soralog/logger.hpp b/include/soralog/logger.hpp index 8105f71..8f41c0b 100644 --- a/include/soralog/logger.hpp +++ b/include/soralog/logger.hpp @@ -29,9 +29,10 @@ namespace soralog { Logger(const Logger &) = delete; ~Logger() = default; Logger &operator=(Logger &&) noexcept = delete; - Logger &operator=(Logger const &) = delete; + Logger &operator=(const Logger &) = delete; - Logger(LoggingSystem &system, std::string logger_name, + Logger(LoggingSystem &system, + std::string logger_name, std::shared_ptr group); private: @@ -40,8 +41,9 @@ namespace soralog { * name and event's data ({@param format} and {@param args}) to sink */ template - void __attribute__((no_sanitize("thread"))) - push(Level level, const Format &format, const Args &...args) { + void __attribute__((no_sanitize("thread"))) push(Level level, + const Format &format, + const Args &...args) { if (level_ >= level) { if (level != Level::OFF and level != Level::IGNORE) { sink_->push(name_, level, format, args...); diff --git a/include/soralog/logger_factory.hpp b/include/soralog/logger_factory.hpp index 2269bb3..282f859 100644 --- a/include/soralog/logger_factory.hpp +++ b/include/soralog/logger_factory.hpp @@ -35,7 +35,8 @@ namespace soralog { * overridden to {@param level} */ [[nodiscard]] virtual std::shared_ptr getLogger( - std::string logger_name, const std::string &group_name, + std::string logger_name, + const std::string &group_name, Level level) = 0; /** @@ -44,7 +45,8 @@ namespace soralog { * overridden to sink with name {@param sink_name} */ [[nodiscard]] virtual std::shared_ptr getLogger( - std::string logger_name, const std::string &group_name, + std::string logger_name, + const std::string &group_name, std::string sink_name) = 0; /** @@ -53,8 +55,10 @@ namespace soralog { * andd level overridden to {@param sink_name} and {@param level} */ [[nodiscard]] virtual std::shared_ptr getLogger( - std::string logger_name, const std::string &group_name, - std::string sink_name, Level level) = 0; + std::string logger_name, + const std::string &group_name, + std::string sink_name, + Level level) = 0; }; } // namespace soralog diff --git a/include/soralog/logging_system.hpp b/include/soralog/logging_system.hpp index b8d41da..55164fd 100644 --- a/include/soralog/logging_system.hpp +++ b/include/soralog/logging_system.hpp @@ -32,7 +32,7 @@ namespace soralog { public: LoggingSystem() = delete; LoggingSystem(const LoggingSystem &) = delete; - LoggingSystem &operator=(LoggingSystem const &) = delete; + LoggingSystem &operator=(const LoggingSystem &) = delete; ~LoggingSystem() override = default; LoggingSystem(LoggingSystem &&tmp) noexcept = delete; LoggingSystem &operator=(LoggingSystem &&tmp) noexcept = delete; @@ -51,8 +51,8 @@ namespace soralog { */ [[nodiscard]] std::shared_ptr getLogger( std::string logger_name, const std::string &group_name) override { - return getLogger(std::move(logger_name), group_name, std::nullopt, - std::nullopt); + return getLogger( + std::move(logger_name), group_name, std::nullopt, std::nullopt); } /** @@ -61,9 +61,12 @@ namespace soralog { * overridden to {@param level} */ [[nodiscard]] std::shared_ptr getLogger( - std::string logger_name, const std::string &group_name, + std::string logger_name, + const std::string &group_name, Level level) override { - return getLogger(std::move(logger_name), group_name, std::nullopt, + return getLogger(std::move(logger_name), + group_name, + std::nullopt, std::make_optional(level)); } @@ -73,10 +76,13 @@ namespace soralog { * overridden to sink with name {@param sink_name} */ [[nodiscard]] std::shared_ptr getLogger( - std::string logger_name, const std::string &group_name, + std::string logger_name, + const std::string &group_name, std::string sink_name) override { - return getLogger(std::move(logger_name), group_name, - std::make_optional(std::move(sink_name)), std::nullopt); + return getLogger(std::move(logger_name), + group_name, + std::make_optional(std::move(sink_name)), + std::nullopt); } /** @@ -85,9 +91,12 @@ namespace soralog { * andd level overridden to {@param sink_name} and {@param level} */ [[nodiscard]] std::shared_ptr getLogger( - std::string logger_name, const std::string &group_name, - std::string sink_name, Level level) override { - return getLogger(std::move(logger_name), group_name, + std::string logger_name, + const std::string &group_name, + std::string sink_name, + Level level) override { + return getLogger(std::move(logger_name), + group_name, std::make_optional(std::move(sink_name)), std::make_optional(level)); } @@ -224,7 +233,8 @@ namespace soralog { * provided or inherits from the group elsewise */ [[nodiscard]] std::shared_ptr getLogger( - std::string logger_name, const std::string &group_name, + std::string logger_name, + const std::string &group_name, const std::optional &sink_name, const std::optional &level); diff --git a/include/soralog/macro.hpp b/include/soralog/macro.hpp index c155e4e..9640a79 100644 --- a/include/soralog/macro.hpp +++ b/include/soralog/macro.hpp @@ -21,13 +21,13 @@ */ #define _SL_LOG_IF_LEVEL(LOG, LVL, FMT, ...) \ - do { \ + ({ \ auto &&_sl_log_log = (LOG); \ soralog::Level _sl_log_level = (LVL); \ if (_sl_log_log->level() >= _sl_log_level) { \ _sl_log_log->log(_sl_log_level, (FMT), ##__VA_ARGS__); \ } \ - } while (false) + }) #define _SL_LOG(LOG, LVL, FMT, ...) \ _SL_LOG_IF_LEVEL((LOG), (LVL), (FMT), ##__VA_ARGS__) diff --git a/include/soralog/sink.hpp b/include/soralog/sink.hpp index 366c0a3..0399a85 100644 --- a/include/soralog/sink.hpp +++ b/include/soralog/sink.hpp @@ -46,7 +46,7 @@ namespace soralog { */ class Sink { public: - enum class ThreadInfoType { + enum class ThreadInfoType : uint8_t { NONE, //!< No log thread info NAME, //!< Log thread name ID //!< Log thread id @@ -56,12 +56,18 @@ namespace soralog { Sink(const Sink &) = delete; Sink(Sink &&) noexcept = delete; virtual ~Sink() = default; - Sink &operator=(Sink const &) = delete; + Sink &operator=(const Sink &) = delete; Sink &operator=(Sink &&) noexcept = delete; - Sink(std::string name, ThreadInfoType thread_info_type, size_t max_events, - size_t max_message_length, size_t max_buffer_size, size_t latency) + Sink(std::string name, + Level level, + ThreadInfoType thread_info_type, + size_t max_events, + size_t max_message_length, + size_t max_buffer_size, + size_t latency) : name_(std::move(name)), + level_(level), thread_info_type_(thread_info_type), max_message_length_(max_message_length), max_buffer_size_(max_buffer_size), @@ -74,14 +80,17 @@ namespace soralog { } } - Sink(std::string name, std::vector> sinks) + Sink(std::string name, + Level level, + std::vector> sinks) : name_(std::move(name)), + level_(level), thread_info_type_(), max_message_length_(), max_buffer_size_(), latency_(), events_(0, 0), - underlying_sinks_(std::move(sinks)){}; + underlying_sinks_(std::move(sinks)) {}; /** * @returns name of sink @@ -90,6 +99,13 @@ namespace soralog { return name_; } + /** + * @returns minimal level which sink will accept + */ + Level level() const noexcept { + return level_; + } + /** * Emplaces new log event * @param name is name of logger @@ -98,13 +114,22 @@ namespace soralog { * @param args arguments is of log message */ template - void push(std::string_view name, Level level, const Format &format, + void push(std::string_view name, + Level level, + const Format &format, const Args &...args) noexcept(IF_RELEASE) { + if (level_ < level or level == Level::OFF or level == Level::IGNORE) { + return; + } if (underlying_sinks_.empty()) { while (true) { { - auto node = events_.put(name, thread_info_type_, level, format, - max_message_length_, args...); + auto node = events_.put(name, + thread_info_type_, + level, + format, + max_message_length_, + args...); // Event is queued successfully LIKELY_IF((bool)node) { @@ -145,22 +170,17 @@ namespace soralog { virtual void rotate() noexcept = 0; protected: - // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) + // NOLINTBEGIN(cppcoreguidelines-non-private-member-variables-in-classes) const std::string name_; - // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) + Level level_; const ThreadInfoType thread_info_type_; - // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) const size_t max_buffer_size_; - // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) const std::chrono::milliseconds latency_; - // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) const size_t max_message_length_; - // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) CircularBuffer events_; - // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) std::atomic_size_t size_ = 0; - // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes) const std::vector> underlying_sinks_{}; + // NOLINTEND(cppcoreguidelines-non-private-member-variables-in-classes) }; } // namespace soralog diff --git a/include/soralog/util.hpp b/include/soralog/util.hpp index 30edd11..87481ea 100644 --- a/include/soralog/util.hpp +++ b/include/soralog/util.hpp @@ -41,7 +41,8 @@ namespace soralog::util { #warning \ "Function getThreadName() is not implemented for current platform; An auto-generated name will be used instead" auto generated = "Thread#" + std::to_string(getThreadNumber()); - memcpy(thr_name.data(), generated.data(), + memcpy(thr_name.data(), + generated.data(), std::min(generated.size(), thr_name.size())); #endif return true; diff --git a/src/group.cpp b/src/group.cpp index 292eed6..cbf3ff7 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -12,7 +12,8 @@ namespace soralog { - Group::Group(LoggingSystem &logging_system, std::string group_name, + Group::Group(LoggingSystem &logging_system, + std::string group_name, const std::optional &parent_name, const std::optional &sink_name, std::optional level) diff --git a/src/impl/configurator_from_yaml.cpp b/src/impl/configurator_from_yaml.cpp index 71402a3..ce887c9 100644 --- a/src/impl/configurator_from_yaml.cpp +++ b/src/impl/configurator_from_yaml.cpp @@ -69,9 +69,9 @@ namespace soralog { try { node = YAML::LoadFile(arg); } catch (const std::exception &exception) { - errors_ << "E: Can't parse file `" - << std::filesystem::canonical(arg).string() - << "': " << exception.what() << "\n"; + errors_ << "E: Can't parse file " + << std::filesystem::weakly_canonical(arg) << ": " + << exception.what() << "\n"; has_error_ = true; } @@ -95,9 +95,10 @@ namespace soralog { result.has_error = result.has_error || has_error_; result.has_warning = result.has_warning || has_warning_; - result.message += (has_error_ or has_warning_) - ? ("I: Some problems are found in config:\n" + errors_.str()) - : ""; + result.message += + (has_error_ or has_warning_) + ? ("I: Some problems are found in config:\n" + errors_.str()) + : ""; return result; } @@ -118,10 +119,12 @@ namespace soralog { for (const auto &it : node) { auto key = it.first.as(); - if (key == "sinks") + if (key == "sinks") { continue; - if (key == "groups") + } + if (key == "groups") { continue; + } errors_ << "W: Unknown property: " << key << "\n"; has_warning_ = true; } @@ -158,6 +161,62 @@ namespace soralog { } } + std::optional ConfiguratorFromYAML::Applicator::parseLevel( + const std::string &target, const YAML::Node &node) { + auto level_node = node["level"]; + if (not level_node.IsDefined()) { + return std::nullopt; + } + if (not level_node.IsScalar()) { + errors_ << "E: Property 'level' of " << target << " is not scalar\n"; + has_error_ = true; + return std::nullopt; + } + + auto level_string = level_node.as(); + + if (level_string == "off") { + return Level::OFF; + } + if (level_string == "critical" || level_string == "crit") { + return Level::CRITICAL; + } + if (level_string == "error") { + return Level::ERROR; + } + if (level_string == "warning" || level_string == "warn") { + return Level::WARN; + } + if (level_string == "info") { + return Level::INFO; + } + if (level_string == "verbose") { + return Level::VERBOSE; + } + if (level_string == "debug" || level_string == "deb") { + if constexpr (debug_level_disable) { + errors_ << "W: Level 'debug' in " << target << " won't work: " + << "it has disabled with compile option" + << "\n"; + has_warning_ = true; + } + return Level::DEBUG; + } + if (level_string == "trace") { + if constexpr (trace_level_disabled) { + errors_ << "W: Level 'trace' in " << target << " won't work: " + << "it has disabled with compile option" + << "\n"; + has_warning_ = true; + } + return Level::TRACE; + } + errors_ << "E: Invalid level in " << target << ": " // + << level_string << "\n"; + has_error_ = true; + return std::nullopt; + } + void ConfiguratorFromYAML::Applicator::parseSink(int number, const YAML::Node &sink) { bool fail = false; @@ -344,28 +403,43 @@ namespace soralog { } } + auto level = parseLevel(fmt::format("sink '{}'", name), sink_node) + .value_or(Level::TRACE); + for (const auto &it : sink_node) { auto key = it.first.as(); auto val = it.second; - if (key == "name") + if (key == "name") { continue; - if (key == "type") + } + if (key == "type") { continue; - if (key == "stream") + } + if (key == "stream") { continue; - if (key == "color") + } + if (key == "color") { continue; - if (key == "thread") + } + if (key == "thread") { continue; - if (key == "capacity") + } + if (key == "capacity") { continue; - if (key == "buffer") + } + if (key == "buffer") { continue; - if (key == "max_message_length") + } + if (key == "max_message_length") { continue; - if (key == "latency") + } + if (key == "latency") { continue; + } + if (key == "level") { + continue; + } errors_ << "W: Unknown property of sink '" << name << "' with type 'console': " << key << "\n"; has_warning_ = true; @@ -377,8 +451,14 @@ namespace soralog { has_warning_ = true; } - system_.makeSink(name, stream_type, color, thread_info_type, - capacity, max_message_length, buffer_size, + system_.makeSink(name, + level, + stream_type, + color, + thread_info_type, + capacity, + max_message_length, + buffer_size, latency); } @@ -492,24 +572,38 @@ namespace soralog { } } + auto level = parseLevel(fmt::format("sink '{}'", name), sink_node) + .value_or(Level::TRACE); + for (const auto &it : sink_node) { auto key = it.first.as(); - if (key == "name") + if (key == "name") { continue; - if (key == "type") + } + if (key == "type") { continue; - if (key == "path") + } + if (key == "path") { continue; - if (key == "thread") + } + if (key == "thread") { continue; - if (key == "capacity") + } + if (key == "capacity") { continue; - if (key == "buffer") + } + if (key == "buffer") { continue; - if (key == "max_message_length") + } + if (key == "max_message_length") { continue; - if (key == "latency") + } + if (key == "latency") { continue; + } + if (key == "level") { + continue; + } errors_ << "W: Unknown property of sink '" << name << "': " << key << "\n"; has_warning_ = true; @@ -527,8 +621,14 @@ namespace soralog { has_warning_ = true; } - system_.makeSink(name, path, thread_info_type, capacity, - max_message_length, buffer_size, latency); + system_.makeSink(name, + level, + path, + thread_info_type, + capacity, + max_message_length, + buffer_size, + latency); } void ConfiguratorFromYAML::Applicator::parseSinkToSyslog( @@ -641,24 +741,38 @@ namespace soralog { } } + auto level = parseLevel(fmt::format("sink '{}'", name), sink_node) + .value_or(Level::TRACE); + for (const auto &it : sink_node) { auto key = it.first.as(); - if (key == "name") + if (key == "name") { continue; - if (key == "type") + } + if (key == "type") { continue; - if (key == "ident") + } + if (key == "ident") { continue; - if (key == "thread") + } + if (key == "thread") { continue; - if (key == "capacity") + } + if (key == "capacity") { continue; - if (key == "buffer") + } + if (key == "buffer") { continue; - if (key == "max_message_length") + } + if (key == "max_message_length") { continue; - if (key == "latency") + } + if (key == "latency") { continue; + } + if (key == "level") { + continue; + } errors_ << "W: Unknown property of sink '" << name << "': " << key << "\n"; has_warning_ = true; @@ -676,8 +790,14 @@ namespace soralog { has_warning_ = true; } - system_.makeSink(name, ident, thread_info_type, capacity, - max_message_length, buffer_size, latency); + system_.makeSink(name, + level, + ident, + thread_info_type, + capacity, + max_message_length, + buffer_size, + latency); } void ConfiguratorFromYAML::Applicator::parseMultisink( @@ -695,14 +815,23 @@ namespace soralog { has_error_ = true; } + auto level = parseLevel(fmt::format("sink '{}'", name), sink_node) + .value_or(Level::TRACE); + for (const auto &it : sink_node) { auto key = it.first.as(); - if (key == "name") + if (key == "name") { + continue; + } + if (key == "type") { continue; - if (key == "type") + } + if (key == "sinks") { continue; - if (key == "sinks") + } + if (key == "level") { continue; + } errors_ << "W: Unknown property of sink '" << name << "': " << key << "\n"; has_warning_ = true; @@ -726,7 +855,7 @@ namespace soralog { } } - system_.makeSink(name, std::move(sinks)); + system_.makeSink(name, level, std::move(sinks)); } void ConfiguratorFromYAML::Applicator::parseGroups( @@ -755,7 +884,8 @@ namespace soralog { } void ConfiguratorFromYAML::Applicator::parseGroup( - int number, const YAML::Node &group_node, + int number, + const YAML::Node &group_node, const std::optional &parent) { bool fail = false; @@ -809,22 +939,13 @@ namespace soralog { sink.emplace("*"); } - std::optional level_string{}; auto level_node = group_node["level"]; - if (level_node.IsDefined()) { - if (not level_node.IsScalar()) { - fail = true; - errors_ << "E: Property 'level' of group " << tmp_name - << " is not scalar\n"; - has_error_ = true; - } else { - level_string.emplace(level_node.as()); - } - } else if (not parent) { + if (not level_node.IsDefined() and not parent) { fail = true; errors_ << "E: Not found 'level' of root group " << tmp_name << "\n"; has_error_ = true; } + auto level = parseLevel(fmt::format("group '{}'", tmp_name), group_node); auto children_node = group_node["children"]; if (children_node.IsDefined()) { @@ -839,16 +960,21 @@ namespace soralog { for (const auto &it : group_node) { auto key = it.first.as(); - if (key == "name") + if (key == "name") { continue; - if (key == "is_fallback") + } + if (key == "is_fallback") { continue; - if (key == "sink") + } + if (key == "sink") { continue; - if (key == "level") + } + if (key == "level") { continue; - if (key == "children") + } + if (key == "children") { continue; + } errors_ << "W: Unknown property of group " << tmp_name << ": " << key << "\n"; has_warning_ = true; @@ -862,43 +988,6 @@ namespace soralog { } } - std::optional level{}; - if (level_string) { - if (level_string == "off") { - level.emplace(Level::OFF); - } else if (level_string == "critical" || level_string == "crit") { - level.emplace(Level::CRITICAL); - } else if (level_string == "error") { - level.emplace(Level::ERROR); - } else if (level_string == "warning" || level_string == "warn") { - level.emplace(Level::WARN); - } else if (level_string == "info") { - level.emplace(Level::INFO); - } else if (level_string == "verbose") { - level.emplace(Level::VERBOSE); - } else if (level_string == "debug" || level_string == "deb") { - level.emplace(Level::DEBUG); - if constexpr (debug_level_disable) { - errors_ << "W: Level 'trace' in group " << tmp_name - << " woun't work: it has disabled with compile option" - << "\n"; - has_warning_ = true; - } - } else if (level_string == "trace") { - level.emplace(Level::TRACE); - if constexpr (trace_level_disabled) { - errors_ << "W: Level 'trace' in group " << tmp_name - << " woun't work: it has disabled with compile option" - << "\n"; - has_warning_ = true; - } - } else { - errors_ << "E: Invalid level in group " << tmp_name << ": " - << *level_string << "\n"; - has_error_ = true; - } - } - if (fail) { errors_ << "W: There are probably more bugs in the group " << tmp_name << "; Fix the existing ones first.\n"; diff --git a/src/impl/fallback_configurator.cpp b/src/impl/fallback_configurator.cpp index 4a8ede8..0d979c1 100644 --- a/src/impl/fallback_configurator.cpp +++ b/src/impl/fallback_configurator.cpp @@ -15,16 +15,17 @@ namespace soralog { Configurator::Result FallbackConfigurator::applyOn( LoggingSystem &system) const { - system.makeSink("console", SinkToConsole::Stream::STDOUT, - with_color_); + system.makeSink( + "console", level_, SinkToConsole::Stream::STDOUT, with_color_); system.makeGroup("*", {}, "console", level_); return {.has_error = false, .has_warning = true, - .message = std::string() + - "I: Using fallback configurator for logger system\n" - "I: All logs will be write into " + (with_color_ ? "color " : "") + - "standard output with '" + levelToStr(level_) + "' level"}; + .message = std::string() + + "I: Using fallback configurator for logger system\n" + "I: All logs will be write into " + + (with_color_ ? "color " : "") + "standard output with '" + + levelToStr(level_) + "' level"}; } } // namespace soralog diff --git a/src/impl/multisink.cpp b/src/impl/multisink.cpp index ca584ba..008213d 100644 --- a/src/impl/multisink.cpp +++ b/src/impl/multisink.cpp @@ -14,8 +14,9 @@ namespace soralog { Multisink::Multisink(std::string name, + Level level, std::vector> sinks) - : Sink(std::move(name), std::move(sinks)) {} + : Sink(std::move(name), level, std::move(sinks)) {} void Multisink::flush() noexcept { for (const auto &sink : underlying_sinks_) { diff --git a/src/impl/sink_to_console.cpp b/src/impl/sink_to_console.cpp index 7e7b048..3304b11 100644 --- a/src/impl/sink_to_console.cpp +++ b/src/impl/sink_to_console.cpp @@ -42,7 +42,7 @@ namespace soralog { }; template - inline void pass(Args &&...styles) {} + inline void pass(const Args...) {} enum V {}; template @@ -68,7 +68,8 @@ namespace soralog { void put_level_style(char *&ptr, Level level) { assert(level <= Level::TRACE); auto color = level_to_color_map[static_cast(level)]; // NOLINT - put_style(ptr, fmt::detail::make_foreground_color(color), + put_style(ptr, + fmt::detail::make_foreground_color(color), fmt::detail::make_emphasis(fmt::emphasis::bold)); } @@ -115,27 +116,35 @@ namespace soralog { template void put_string(char *&ptr, const T &name, size_t width) { - if (width == 0) + if (width == 0) { return; + } for (auto c : name) { - if (c == '\0' or width == 0) + if (c == '\0' or width == 0) { break; + } *ptr++ = c; // NOLINT --width; } - while (width--) *ptr++ = ' '; // NOLINT + while (width--) { + *ptr++ = ' '; // NOLINT + } } } // namespace - SinkToConsole::SinkToConsole(std::string name, Stream stream_type, + SinkToConsole::SinkToConsole(std::string name, + Level level, + Stream stream_type, bool with_color, std::optional thread_info_type, std::optional capacity, std::optional max_message_length, std::optional buffer_size, std::optional latency) - : Sink(std::move(name), thread_info_type.value_or(ThreadInfoType::NONE), + : Sink(std::move(name), + level, + thread_info_type.value_or(ThreadInfoType::NONE), capacity.value_or(1u << 6), // 64 events max_message_length.value_or(1u << 10), // 1024 bytes buffer_size.value_or(1u << 17), // 128 Kb @@ -194,10 +203,15 @@ namespace soralog { if (psec != sec) { tm = fmt::localtime(sec); - fmt::format_to_n(datetime.data(), datetime.size(), + fmt::format_to_n(datetime.data(), + datetime.size(), "{:0>2}.{:0>2}.{:0>2} {:0>2}:{:0>2}:{:0>2}", - tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); + tm.tm_year % 100, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec); psec = sec; } @@ -211,8 +225,8 @@ namespace soralog { fmt::detail::make_foreground_color(fmt::color::gray); auto size = std::end(style) - std::begin(style); - std::memcpy(ptr, std::begin(style), - std::end(style) - std::begin(style)); + std::memcpy( + ptr, std::begin(style), std::end(style) - std::begin(style)); ptr = ptr + size; // NOLINT } @@ -233,8 +247,8 @@ namespace soralog { break; case ThreadInfoType::ID: - ptr = fmt::format_to_n(ptr, end - ptr, "T:{:<6}", - event.thread_number()) + ptr = fmt::format_to_n( + ptr, end - ptr, "T:{:<6}", event.thread_number()) .out; put_separator(ptr); break; @@ -285,7 +299,7 @@ namespace soralog { if ((end - ptr) < sizeof(Event) or appended or std::chrono::steady_clock::now() - >= next_flush_.load(std::memory_order_acquire)) { + >= next_flush_.load(std::memory_order_acquire)) { next_flush_.store(std::chrono::steady_clock::now() + latency_, std::memory_order_release); stream_.write(begin, ptr - begin); @@ -294,8 +308,8 @@ namespace soralog { if (appended) { bool true_v = true; - if (need_to_flush_.compare_exchange_weak(true_v, false, - std::memory_order_acq_rel)) { + if (need_to_flush_.compare_exchange_weak( + true_v, false, std::memory_order_acq_rel)) { stream_.flush(); } } diff --git a/src/impl/sink_to_file.cpp b/src/impl/sink_to_file.cpp index 84e5ecd..4aae0ea 100644 --- a/src/impl/sink_to_file.cpp +++ b/src/impl/sink_to_file.cpp @@ -53,26 +53,34 @@ namespace soralog { template void put_string(char *&ptr, const T &name, size_t width) { - if (width == 0) + if (width == 0) { return; + } for (auto c : name) { - if (c == '\0' or width == 0) + if (c == '\0' or width == 0) { break; + } *ptr++ = c; // NOLINT --width; } - while (width--) *ptr++ = ' '; // NOLINT + while (width--) { + *ptr++ = ' '; // NOLINT + } } } // namespace - SinkToFile::SinkToFile(std::string name, std::filesystem::path path, + SinkToFile::SinkToFile(std::string name, + Level level, + std::filesystem::path path, std::optional thread_info_type, std::optional capacity, std::optional max_message_length, std::optional buffer_size, std::optional latency) - : Sink(std::move(name), thread_info_type.value_or(ThreadInfoType::NONE), + : Sink(std::move(name), + level, + thread_info_type.value_or(ThreadInfoType::NONE), capacity.value_or(1u << 11), // 2048 events max_message_length.value_or(1u << 10), // 1024 bytes buffer_size.value_or(1u << 22), // 4 Mb @@ -82,7 +90,7 @@ namespace soralog { out_.open(path_, std::ios::app); if (not out_.is_open()) { std::cerr << "Can't open log file '" << path_ << "': " << strerror(errno) - << std::endl; + << '\n'; } else if (latency_ != std::chrono::milliseconds::zero()) { sink_worker_ = std::make_unique([this] { run(); }); } @@ -134,10 +142,15 @@ namespace soralog { if (psec != sec) { tm = fmt::localtime(sec); - fmt::format_to_n(datetime.data(), datetime.size(), + fmt::format_to_n(datetime.data(), + datetime.size(), "{:0>2}.{:0>2}.{:0>2} {:0>2}:{:0>2}:{:0>2}", - tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); + tm.tm_year % 100, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec); psec = sec; } @@ -159,8 +172,8 @@ namespace soralog { break; case ThreadInfoType::ID: - ptr = fmt::format_to_n(ptr, end - ptr, "T:{:<6}", - event.thread_number()) + ptr = fmt::format_to_n( + ptr, end - ptr, "T:{:<6}", event.thread_number()) .out; put_separator(ptr); break; @@ -190,7 +203,7 @@ namespace soralog { if ((end - ptr) < sizeof(Event) or appended or std::chrono::steady_clock::now() - >= next_flush_.load(std::memory_order_acquire)) { + >= next_flush_.load(std::memory_order_acquire)) { next_flush_.store(std::chrono::steady_clock::now() + latency_, std::memory_order_release); out_.write(begin, ptr - begin); @@ -199,8 +212,8 @@ namespace soralog { if (appended) { bool true_v = true; - if (need_to_flush_.compare_exchange_weak(true_v, false, - std::memory_order_acq_rel)) { + if (need_to_flush_.compare_exchange_weak( + true_v, false, std::memory_order_acq_rel)) { out_.flush(); } } @@ -209,18 +222,19 @@ namespace soralog { } bool true_v = true; - if (need_to_rotate_.compare_exchange_weak(true_v, false, - std::memory_order_acq_rel)) { + if (need_to_rotate_.compare_exchange_weak( + true_v, false, std::memory_order_acq_rel)) { std::ofstream out; out.open(path_, std::ios::app); if (not out.is_open()) { if (out_.is_open()) { std::cerr << "Can't re-open log file '" << path_ - << "': " << strerror(errno) << std::endl; + << "': " << strerror(errno) << '\n'; } else { std::cerr << "Can't open log file '" << path_ - << "': " << strerror(errno) << std::endl; + << "': " << strerror(errno) << '\n'; } + std::cerr.flush(); } else { std::swap(out_, out); } diff --git a/src/impl/sink_to_nowhere.cpp b/src/impl/sink_to_nowhere.cpp index f9ca993..69b61c5 100644 --- a/src/impl/sink_to_nowhere.cpp +++ b/src/impl/sink_to_nowhere.cpp @@ -12,7 +12,13 @@ namespace soralog { using namespace std::chrono_literals; SinkToNowhere::SinkToNowhere(std::string name) - : Sink(std::move(name), ThreadInfoType::NONE, 1024, 0, 0, 1000) {} + : Sink(std::move(name), + Level::OFF, + ThreadInfoType::NONE, + 1024, + 0, + 0, + 1000) {} SinkToNowhere::~SinkToNowhere() { flush(); diff --git a/src/impl/sink_to_syslog.cpp b/src/impl/sink_to_syslog.cpp index 3f1afaa..0eb55aa 100644 --- a/src/impl/sink_to_syslog.cpp +++ b/src/impl/sink_to_syslog.cpp @@ -52,15 +52,19 @@ namespace soralog { template void put_string(char *&ptr, const T &name, size_t width) { - if (width == 0) + if (width == 0) { return; + } for (auto c : name) { - if (c == '\0' or width == 0) + if (c == '\0' or width == 0) { break; + } *ptr++ = c; // NOLINT --width; } - while (width--) *ptr++ = ' '; // NOLINT + while (width--) { + *ptr++ = ' '; // NOLINT + } } } // namespace @@ -68,13 +72,17 @@ namespace soralog { // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) std::atomic_bool SinkToSyslog::syslog_is_opened_{false}; - SinkToSyslog::SinkToSyslog(std::string name, std::string ident, + SinkToSyslog::SinkToSyslog(std::string name, + Level level, + std::string ident, std::optional thread_info_type, std::optional capacity, std::optional max_message_length, std::optional buffer_size, std::optional latency) - : Sink(std::move(name), thread_info_type.value_or(ThreadInfoType::NONE), + : Sink(std::move(name), + level, + thread_info_type.value_or(ThreadInfoType::NONE), capacity.value_or(1u << 11), // 2048 events max_message_length.value_or(1u << 10), // 1024 bytes buffer_size.value_or(1u << 22), // 4 Mb @@ -142,10 +150,15 @@ namespace soralog { if (psec != sec) { tm = fmt::localtime(sec); - fmt::format_to_n(datetime.data(), datetime.size(), + fmt::format_to_n(datetime.data(), + datetime.size(), "{:0>2}.{:0>2}.{:0>2} {:0>2}:{:0>2}:{:0>2}", - tm.tm_year % 100, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); + tm.tm_year % 100, + tm.tm_mon + 1, + tm.tm_mday, + tm.tm_hour, + tm.tm_min, + tm.tm_sec); psec = sec; } diff --git a/src/logger.cpp b/src/logger.cpp index a37ca73..32e58c7 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -12,7 +12,8 @@ namespace soralog { - Logger::Logger(soralog::LoggingSystem &system, std::string logger_name, + Logger::Logger(soralog::LoggingSystem &system, + std::string logger_name, std::shared_ptr group) : system_(system), name_(std::move(logger_name)), diff --git a/src/logging_system.cpp b/src/logging_system.cpp index d0d7a24..6a4b8e5 100644 --- a/src/logging_system.cpp +++ b/src/logging_system.cpp @@ -16,15 +16,17 @@ #include #include -namespace soralog { +using std::literals::string_literals::operator""s; +namespace soralog { LoggingSystem::LoggingSystem(std::shared_ptr configurator) : configurator_(std::move(configurator)) { makeSink("*"); } std::shared_ptr LoggingSystem::makeGroup( - std::string name, const std::optional &parent, + std::string name, + const std::optional &parent, const std::optional &sink, const std::optional &level) { auto group = @@ -62,7 +64,16 @@ namespace soralog { throw std::logic_error("LoggerSystem is already configured"); } is_configured_ = true; - auto result = configurator_->applyOn(*this); + + Configurator::Result result; + try { + result = configurator_->applyOn(*this); + } catch (const std::exception &exception) { + result.message += "E: Configure is failed: "s + exception.what() + "; " + + "Logging system is unworkable\n"; + result.has_error = true; + return result; + } if (groups_.empty()) { result.message += @@ -76,9 +87,8 @@ namespace soralog { continue; } if (group->sink()->name() == "*") { - result.message += - "W: Group '" + name + "' has undefined sink; " - "Sink to nowhere will be used\n"; + result.message += "W: Group '" + name + "' has undefined sink; " + + "Sink to nowhere will be used\n"; result.has_warning = true; } } @@ -87,7 +97,8 @@ namespace soralog { } std::shared_ptr LoggingSystem::getLogger( - std::string logger_name, const std::string &group_name, + std::string logger_name, + const std::string &group_name, const std::optional &sink_name, const std::optional &level) { std::lock_guard guard(mutex_); @@ -122,11 +133,13 @@ namespace soralog { logger->warn( "Group '{}' for logger '{}' is not found. " "Fallback group will be used (it is group '{}' right now).", - group_name, logger_name, group->name()); + group_name, + logger_name, + group->name()); } - auto logger = std::make_shared(*this, std::move(logger_name), - std::move(group)); + auto logger = std::make_shared( + *this, std::move(logger_name), std::move(group)); if (sink_name.has_value()) { logger->setSink(sink_name.value()); diff --git a/test/mock/sink_mock.hpp b/test/mock/sink_mock.hpp index 139353f..aa4cc9b 100644 --- a/test/mock/sink_mock.hpp +++ b/test/mock/sink_mock.hpp @@ -18,11 +18,19 @@ namespace soralog { public: SinkMock(std::string name) - : Sink(std::move(name), ThreadInfoType::NONE, 4, 1024, 4096, 0) {} + : Sink(std::move(name), + Level::TRACE, + ThreadInfoType::NONE, + 4, + 1024, + 4096, + 0) {} ~SinkMock() override = default; template - void push(std::string_view name, Level level, std::string_view format, + void push(std::string_view name, + Level level, + std::string_view format, size_t max_message_length, const Args &...args) noexcept(IF_RELEASE) { mocked_push(name, level, format); diff --git a/test/unit/circular_buffer_test.cpp b/test/unit/circular_buffer_test.cpp index 954d6cd..ab8ddf0 100644 --- a/test/unit/circular_buffer_test.cpp +++ b/test/unit/circular_buffer_test.cpp @@ -55,7 +55,7 @@ TEST_F(CircularBufferTest, Put) { EXPECT_EQ(testee.avail(), capacity - i); EXPECT_EQ(testee.capacity(), capacity); - std::cout << "--- put #" << (i + 1) << std::endl; + std::cout << "--- put #" << (i + 1) << '\n'; auto ref = testee.put('1' + i); EXPECT_TRUE(ref); } @@ -65,14 +65,14 @@ TEST_F(CircularBufferTest, Put) { EXPECT_EQ(testee.capacity(), capacity); // Overfill - std::cout << "--- put #" << (capacity + 1) << " (overfill)" << std::endl; + std::cout << "--- put #" << (capacity + 1) << " (overfill)" << '\n'; auto ref = testee.put('1' + capacity); EXPECT_FALSE(ref); EXPECT_EQ(testee.size(), capacity); EXPECT_EQ(testee.avail(), 0); EXPECT_EQ(testee.capacity(), capacity); - std::cout << '\n' << std::endl; + std::cout << '\n' << '\n'; } TEST_F(CircularBufferTest, Get) { @@ -85,7 +85,7 @@ TEST_F(CircularBufferTest, Get) { EXPECT_EQ(testee.avail(), capacity); EXPECT_EQ(testee.capacity(), capacity); - std::cout << "--- get (nothing actually)" << std::endl; + std::cout << "--- get (nothing actually)" << '\n'; auto ref = testee.get(); EXPECT_FALSE(ref); } @@ -101,7 +101,7 @@ TEST_F(CircularBufferTest, Get) { EXPECT_EQ(testee.avail(), i); EXPECT_EQ(testee.capacity(), capacity); - std::cout << "--- get #" << (i + 1) << std::endl; + std::cout << "--- get #" << (i + 1) << '\n'; auto ref = testee.get(); EXPECT_TRUE(ref); @@ -127,7 +127,7 @@ TEST_F(CircularBufferTest, PutGet) { std::cout << "[lag=" << lag << "]: " // << "put " << ref_put->c() << " > " // << "size=" << testee.size() << " avail=" << testee.avail() - << std::endl; + << '\n'; } for (auto n = 0; n < capacity; ++n) { { @@ -137,7 +137,7 @@ TEST_F(CircularBufferTest, PutGet) { std::cout << "[lag=" << lag << "]: " // << "put " << ref_put->c() << " > " // << "size=" << testee.size() << " avail=" << testee.avail() - << std::endl; + << '\n'; } { auto ref_get = testee.get(); @@ -145,7 +145,7 @@ TEST_F(CircularBufferTest, PutGet) { std::cout << "[lag=" << lag << "]: " // << "get " << ref_get->c() << " > " // << "size=" << testee.size() << " avail=" << testee.avail() - << std::endl; + << '\n'; } } } @@ -168,13 +168,13 @@ TEST_F(CircularBufferTest, PutGetMt) { latch.arrive_and_wait(); #endif while (i < n) { - std::cout << "w" << i << std::endl; + std::cout << "w" << i << '\n'; // if (auto ref = testee.put('0' + (i % 10))) { if (auto ref = testee.put('0')) { ++i; std::cout << "put " << ref->c() // << " [" << testee.size() << " | " << testee.avail() << "]" - << std::endl; + << '\n'; } std::this_thread::sleep_for(std::chrono::milliseconds(3 + random() % 50)); } @@ -185,11 +185,11 @@ TEST_F(CircularBufferTest, PutGetMt) { latch.arrive_and_wait(); #endif while (i < n) { - std::cout << "r" << std::endl; + std::cout << "r" << '\n'; if (auto ref = testee.get()) { std::cout << "get " << ref->c() // << " [" << testee.size() << " | " << testee.avail() << "]" - << std::endl; + << '\n'; } std::this_thread::sleep_for(std::chrono::milliseconds(3 + random() % 50)); } @@ -218,7 +218,7 @@ TEST_F(CircularBufferTest, Mutual) { if (auto ref = testee.put('*')) { std::cout << "put " << ref->c() // << " [" << testee.size() << " | " << testee.avail() << "]" - << std::endl; + << '\n'; std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } }); @@ -231,7 +231,7 @@ TEST_F(CircularBufferTest, Mutual) { if (auto ref = testee.get()) { std::cout << "get " << ref->c() // << " [" << testee.size() << " | " << testee.avail() << "]" - << std::endl; + << '\n'; } }); diff --git a/test/unit/sink_to_console_test.cpp b/test/unit/sink_to_console_test.cpp index 1ed3e9f..88f8608 100644 --- a/test/unit/sink_to_console_test.cpp +++ b/test/unit/sink_to_console_test.cpp @@ -39,6 +39,7 @@ class SinkToConsoleTest : public ::testing::Test { std::shared_ptr createLogger(std::chrono::milliseconds latency) { auto sink = std::make_shared( "console", + Level::TRACE, SinkToConsole::Stream::STDOUT, // standard output stream false, // no color Sink::ThreadInfoType::ID, // ignore thread info @@ -56,8 +57,8 @@ TEST_F(SinkToConsoleTest, Logging) { int count = 100; for (int round = 1; round <= 3; ++round) { for (int i = 1; i <= count; ++i) { - logger->debug("round: {}, message: {}, delay: {}ms", round, i, - abs(i - count / 2)); + logger->debug( + "round: {}, message: {}, delay: {}ms", round, i, abs(i - count / 2)); std::this_thread::sleep_for(delay * abs(i - count / 2)); } } diff --git a/test/unit/sink_to_file_test.cpp b/test/unit/sink_to_file_test.cpp index afa56f7..91cfb30 100644 --- a/test/unit/sink_to_file_test.cpp +++ b/test/unit/sink_to_file_test.cpp @@ -47,7 +47,9 @@ class SinkToFileTest : public ::testing::Test { std::shared_ptr createLogger(std::chrono::milliseconds latency) { auto sink = std::make_shared( - "file", path_, + "file", + Level::TRACE, + path_, Sink::ThreadInfoType::NONE, // ignore thread info 4, // capacity: 4 events 64, // max message length: 64 byte @@ -66,8 +68,8 @@ TEST_F(SinkToFileTest, Logging) { int count = 100; for (int round = 1; round <= 3; ++round) { for (int i = 1; i <= count; ++i) { - logger->debug("round: {}, message: {}, delay: {}ms", round, i, - abs(i - count / 2)); + logger->debug( + "round: {}, message: {}, delay: {}ms", round, i, abs(i - count / 2)); std::this_thread::sleep_for(delay * abs(i - count / 2)); } }