From 832483e7f5511879aff71e873b0ea8a2073047c5 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Tue, 10 Jun 2025 16:46:32 -0500 Subject: [PATCH 01/34] Spectator2.0 (#121) This imports the work on spectator-cpp 2.0 from an external staging repo to the main repo. --- .clang-format | 88 ----- .github/workflows/build.yml | 43 --- .gitignore | 3 +- CMakeLists.txt | 78 +--- Dockerfiles/README.md | 32 ++ Dockerfiles/Ubuntu.Dockerfile | 25 ++ Dockerfiles/Ubuntu.Dockerfile.dockerignore | 2 + LICENSE | 2 +- OSSMETADATA | 2 +- README.md | 67 +--- build.sh | 28 +- conanfile.py | 7 +- libs/CMakeLists.txt | 5 + libs/README.md | 21 ++ libs/config/CMakeLists.txt | 24 ++ libs/config/README.md | 69 ++++ libs/config/include/config.h | 32 ++ libs/config/src/config.cpp | 39 ++ libs/config/test/test_config.cpp | 209 ++++++++++ libs/logger/CMakeLists.txt | 12 + libs/logger/logger.h | 93 +++++ libs/meter/CMakeLists.txt | 2 + libs/meter/meter_id/CMakeLists.txt | 18 + libs/meter/meter_id/include/meter_id.h | 48 +++ libs/meter/meter_id/src/meter_id.cpp | 108 ++++++ libs/meter/meter_id/test/test_meter_id.cpp | 109 ++++++ libs/meter/meter_types/CMakeLists.txt | 41 ++ libs/meter/meter_types/include/age_gauge.h | 29 ++ libs/meter/meter_types/include/base/meter.h | 29 ++ libs/meter/meter_types/include/counter.h | 26 ++ libs/meter/meter_types/include/dist_summary.h | 26 ++ libs/meter/meter_types/include/gauge.h | 26 ++ libs/meter/meter_types/include/max_gauge.h | 23 ++ libs/meter/meter_types/include/meter_types.h | 15 + .../meter_types/include/monotonic_counter.h | 23 ++ .../include/monotonic_counter_uint.h | 23 ++ .../include/percentile_dist_summary.h | 27 ++ .../meter_types/include/percentile_timer.h | 26 ++ libs/meter/meter_types/include/timer.h | 26 ++ .../meter/meter_types/test/test_age_gauge.cpp | 30 ++ libs/meter/meter_types/test/test_counter.cpp | 33 ++ .../meter_types/test/test_dist_summary.cpp | 43 +++ libs/meter/meter_types/test/test_gauge.cpp | 30 ++ .../meter/meter_types/test/test_max_gauge.cpp | 20 + .../test/test_monotonic_counter.cpp | 30 ++ .../test/test_monotonic_counter_uint.cpp | 32 ++ .../test/test_percentile_dist_summary.cpp | 43 +++ .../test/test_percentile_timer.cpp | 43 +++ libs/meter/meter_types/test/test_timer.cpp | 43 +++ libs/utils/CMakeLists.txt | 15 + libs/utils/include/singleton.h | 22 ++ libs/utils/include/util.h | 50 +++ libs/utils/src/util.cpp | 57 +++ libs/writer/CMakeLists.txt | 3 + libs/writer/writer_config/CMakeLists.txt | 29 ++ .../writer_config/include/writer_config.h | 20 + .../writer_config/src/writer_config.cpp | 52 +++ .../writer_config/test/test_writer_config.cpp | 169 +++++++++ libs/writer/writer_types/CMakeLists.txt | 55 +++ .../writer_types/include/base/base_writer.h | 18 + .../writer_types/include/memory_writer.h | 28 ++ libs/writer/writer_types/include/udp_writer.h | 22 ++ libs/writer/writer_types/include/uds_writer.h | 25 ++ .../writer_types/include/writer_types.h | 43 +++ .../writer/writer_types/src/memory_writer.cpp | 33 ++ libs/writer/writer_types/src/udp_writer.cpp | 81 ++++ libs/writer/writer_types/src/uds_writer.cpp | 116 ++++++ .../writer_types/test/test_memory_writer.cpp | 50 +++ .../writer_types/test/test_udp_writer.cpp | 137 +++++++ .../writer_types/test/test_uds_writer.cpp | 139 +++++++ .../writer_types/test_utils/CMakeLists.txt | 2 + .../test_utils/udp_server/CMakeLists.txt | 31 ++ .../test_utils/udp_server/udp_server.cpp | 126 +++++++ .../test_utils/udp_server/udp_server.h | 17 + .../test_utils/uds_server/CMakeLists.txt | 31 ++ .../test_utils/uds_server/uds_server.cpp | 153 ++++++++ .../test_utils/uds_server/uds_server.h | 17 + libs/writer/writer_wrapper/CMakeLists.txt | 9 + libs/writer/writer_wrapper/include/Writer.h | 56 +++ .../include/writer_test_helper.h | 31 ++ libs/writer/writer_wrapper/src/Writer.cpp | 111 ++++++ requirements.txt | 2 +- sanitized | 9 - setup-venv.sh | 2 +- spectator/CMakeLists.txt | 24 ++ spectator/age_gauge_test.cc | 36 -- spectator/config.h | 14 - spectator/counter_test.cc | 42 --- spectator/dist_summary_test.cc | 33 -- spectator/gauge_test.cc | 51 --- spectator/id.h | 223 ----------- spectator/id_test.cc | 42 --- spectator/include/registry.h | 76 ++++ spectator/log_entry.h | 68 ---- spectator/logger.cc | 29 -- spectator/logger.h | 22 -- spectator/max_gauge_test.cc | 35 -- spectator/measurement.h | 25 -- spectator/meter_type.h | 60 --- spectator/meter_type_test.cc | 11 - spectator/monotonic_counter_test.cc | 34 -- spectator/monotonic_counter_uint_test.cc | 34 -- spectator/perc_dist_summary_test.cc | 31 -- spectator/perc_timer_test.cc | 30 -- spectator/publisher.cc | 166 -------- spectator/publisher.h | 58 --- spectator/publisher_test.cc | 166 -------- spectator/registry.h | 356 ------------------ spectator/src/registry.cpp | 129 +++++++ spectator/stateful_meters.h | 299 --------------- spectator/stateful_test.cc | 35 -- spectator/stateless_meters.h | 256 ------------- spectator/statelessregistry_test.cc | 219 ----------- spectator/test/test_registry.cpp | 342 +++++++++++++++++ spectator/test_main.cc | 8 - spectator/test_publisher.h | 17 - spectator/test_server.h | 68 ---- spectator/timer_test.cc | 32 -- spectator/util.h | 16 - tools/gen_valid_chars.cc | 48 --- 120 files changed, 3893 insertions(+), 2856 deletions(-) delete mode 100644 .clang-format delete mode 100644 .github/workflows/build.yml create mode 100644 Dockerfiles/README.md create mode 100644 Dockerfiles/Ubuntu.Dockerfile create mode 100644 Dockerfiles/Ubuntu.Dockerfile.dockerignore create mode 100644 libs/CMakeLists.txt create mode 100644 libs/README.md create mode 100644 libs/config/CMakeLists.txt create mode 100644 libs/config/README.md create mode 100644 libs/config/include/config.h create mode 100644 libs/config/src/config.cpp create mode 100644 libs/config/test/test_config.cpp create mode 100644 libs/logger/CMakeLists.txt create mode 100644 libs/logger/logger.h create mode 100644 libs/meter/CMakeLists.txt create mode 100644 libs/meter/meter_id/CMakeLists.txt create mode 100644 libs/meter/meter_id/include/meter_id.h create mode 100644 libs/meter/meter_id/src/meter_id.cpp create mode 100644 libs/meter/meter_id/test/test_meter_id.cpp create mode 100644 libs/meter/meter_types/CMakeLists.txt create mode 100644 libs/meter/meter_types/include/age_gauge.h create mode 100644 libs/meter/meter_types/include/base/meter.h create mode 100644 libs/meter/meter_types/include/counter.h create mode 100644 libs/meter/meter_types/include/dist_summary.h create mode 100644 libs/meter/meter_types/include/gauge.h create mode 100644 libs/meter/meter_types/include/max_gauge.h create mode 100644 libs/meter/meter_types/include/meter_types.h create mode 100644 libs/meter/meter_types/include/monotonic_counter.h create mode 100644 libs/meter/meter_types/include/monotonic_counter_uint.h create mode 100644 libs/meter/meter_types/include/percentile_dist_summary.h create mode 100644 libs/meter/meter_types/include/percentile_timer.h create mode 100644 libs/meter/meter_types/include/timer.h create mode 100644 libs/meter/meter_types/test/test_age_gauge.cpp create mode 100644 libs/meter/meter_types/test/test_counter.cpp create mode 100644 libs/meter/meter_types/test/test_dist_summary.cpp create mode 100644 libs/meter/meter_types/test/test_gauge.cpp create mode 100644 libs/meter/meter_types/test/test_max_gauge.cpp create mode 100644 libs/meter/meter_types/test/test_monotonic_counter.cpp create mode 100644 libs/meter/meter_types/test/test_monotonic_counter_uint.cpp create mode 100644 libs/meter/meter_types/test/test_percentile_dist_summary.cpp create mode 100644 libs/meter/meter_types/test/test_percentile_timer.cpp create mode 100644 libs/meter/meter_types/test/test_timer.cpp create mode 100644 libs/utils/CMakeLists.txt create mode 100644 libs/utils/include/singleton.h create mode 100644 libs/utils/include/util.h create mode 100644 libs/utils/src/util.cpp create mode 100644 libs/writer/CMakeLists.txt create mode 100644 libs/writer/writer_config/CMakeLists.txt create mode 100644 libs/writer/writer_config/include/writer_config.h create mode 100644 libs/writer/writer_config/src/writer_config.cpp create mode 100644 libs/writer/writer_config/test/test_writer_config.cpp create mode 100644 libs/writer/writer_types/CMakeLists.txt create mode 100644 libs/writer/writer_types/include/base/base_writer.h create mode 100644 libs/writer/writer_types/include/memory_writer.h create mode 100644 libs/writer/writer_types/include/udp_writer.h create mode 100644 libs/writer/writer_types/include/uds_writer.h create mode 100644 libs/writer/writer_types/include/writer_types.h create mode 100644 libs/writer/writer_types/src/memory_writer.cpp create mode 100644 libs/writer/writer_types/src/udp_writer.cpp create mode 100644 libs/writer/writer_types/src/uds_writer.cpp create mode 100644 libs/writer/writer_types/test/test_memory_writer.cpp create mode 100644 libs/writer/writer_types/test/test_udp_writer.cpp create mode 100644 libs/writer/writer_types/test/test_uds_writer.cpp create mode 100644 libs/writer/writer_types/test_utils/CMakeLists.txt create mode 100644 libs/writer/writer_types/test_utils/udp_server/CMakeLists.txt create mode 100644 libs/writer/writer_types/test_utils/udp_server/udp_server.cpp create mode 100644 libs/writer/writer_types/test_utils/udp_server/udp_server.h create mode 100644 libs/writer/writer_types/test_utils/uds_server/CMakeLists.txt create mode 100644 libs/writer/writer_types/test_utils/uds_server/uds_server.cpp create mode 100644 libs/writer/writer_types/test_utils/uds_server/uds_server.h create mode 100644 libs/writer/writer_wrapper/CMakeLists.txt create mode 100644 libs/writer/writer_wrapper/include/Writer.h create mode 100644 libs/writer/writer_wrapper/include/writer_test_helper.h create mode 100644 libs/writer/writer_wrapper/src/Writer.cpp delete mode 100644 sanitized mode change 100755 => 100644 setup-venv.sh create mode 100644 spectator/CMakeLists.txt delete mode 100644 spectator/age_gauge_test.cc delete mode 100644 spectator/config.h delete mode 100644 spectator/counter_test.cc delete mode 100644 spectator/dist_summary_test.cc delete mode 100644 spectator/gauge_test.cc delete mode 100644 spectator/id.h delete mode 100644 spectator/id_test.cc create mode 100644 spectator/include/registry.h delete mode 100644 spectator/log_entry.h delete mode 100644 spectator/logger.cc delete mode 100644 spectator/logger.h delete mode 100644 spectator/max_gauge_test.cc delete mode 100644 spectator/measurement.h delete mode 100644 spectator/meter_type.h delete mode 100644 spectator/meter_type_test.cc delete mode 100644 spectator/monotonic_counter_test.cc delete mode 100644 spectator/monotonic_counter_uint_test.cc delete mode 100644 spectator/perc_dist_summary_test.cc delete mode 100644 spectator/perc_timer_test.cc delete mode 100644 spectator/publisher.cc delete mode 100644 spectator/publisher.h delete mode 100644 spectator/publisher_test.cc delete mode 100644 spectator/registry.h create mode 100644 spectator/src/registry.cpp delete mode 100644 spectator/stateful_meters.h delete mode 100644 spectator/stateful_test.cc delete mode 100644 spectator/stateless_meters.h delete mode 100644 spectator/statelessregistry_test.cc create mode 100644 spectator/test/test_registry.cpp delete mode 100644 spectator/test_main.cc delete mode 100644 spectator/test_publisher.h delete mode 100644 spectator/test_server.h delete mode 100644 spectator/timer_test.cc delete mode 100644 spectator/util.h delete mode 100644 tools/gen_valid_chars.cc diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 865f732..0000000 --- a/.clang-format +++ /dev/null @@ -1,88 +0,0 @@ ---- -Language: Cpp -# BasedOnStyle: Google -AccessModifierOffset: -1 -AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: None -AlignConsecutiveDeclarations: None -AlignOperands: true -AlignTrailingComments: true -AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: Never -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: All -AllowShortIfStatementsOnASingleLine: true -AllowShortLoopsOnASingleLine: true -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: Yes -BinPackArguments: true -BinPackParameters: true -BraceWrapping: - AfterClass: false - AfterControlStatement: Never - AfterEnum: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - BeforeCatch: false - BeforeElse: false - IndentBraces: false -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Attach -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -ColumnLimit: 100 -CommentPragmas: '^ IWYU pragma:' -ConstructorInitializerAllOnOneLineOrOnePerLine: true -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: false -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] -IncludeCategories: - - Regex: '^<.*\.h>' - Priority: 1 - - Regex: '^<.*' - Priority: 2 - - Regex: '.*' - Priority: 3 -IndentCaseLabels: true -IndentWidth: 2 -IndentWrappedFunctionNames: false -KeepEmptyLinesAtTheStartOfBlocks: false -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: false -PenaltyBreakBeforeFirstCallParameter: 1 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 200 -PointerAlignment: Left -ReflowComments: true -SortIncludes: Never -SpaceAfterCStyleCast: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 2 -SpacesInAngles: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -Standard: Auto -TabWidth: 8 -UseTab: Never -... diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 01ef513..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,43 +0,0 @@ -name: Build - -on: - pull_request: - push: - branches: - - main - -jobs: - build: - if: ${{ github.repository == 'Netflix/spectator-cpp' }} - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Restore Conan Cache - id: conan-cache-restore - uses: actions/cache/restore@v4 - with: - path: | - /home/runner/.conan2 - /home/runner/work/spectator-cpp/spectator-cpp/cmake-build - key: ${{ runner.os }}-conan - - - name: Install System Dependencies - run: | - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test - sudo apt-get update && sudo apt-get install -y binutils-dev g++-13 libiberty-dev - - - name: Build - run: | - ./setup-venv.sh - source venv/bin/activate - ./build.sh - - - name: Save Conan Cache - id: conan-cache-save - uses: actions/cache/save@v4 - with: - path: | - /home/runner/.conan2 - /home/runner/work/spectator-cpp/spectator-cpp/cmake-build - key: ${{ steps.conan-cache-restore.outputs.cache-primary-key }} diff --git a/.gitignore b/.gitignore index faa4c63..b193668 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ .DS_Store .idea/ +.vscode/ CMakeUserPresets.json cmake-build/ conan_provider.cmake spectator/valid_chars.inc -venv/ +venv/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ae3e8c..84a356f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,70 +1,26 @@ -cmake_minimum_required(VERSION 3.23) - -project(spectator-cpp) +# filepath: /home/ebadeaux/Saturday/spec2-cpp/CMakeLists.txt +cmake_minimum_required(VERSION 3.15) +project(spectator-cpp VERSION 2.0 LANGUAGES CXX) +# Set C++ standard set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -add_compile_options(-pedantic -Werror -Wall -Wno-missing-braces -fno-omit-frame-pointer "$<$:-fsanitize=address>") +# Options +option(BUILD_TESTS "Build the test suite" ON) -find_package(absl REQUIRED) -find_package(asio REQUIRED) -find_package(Backward REQUIRED) -find_package(fmt REQUIRED) -find_package(GTest REQUIRED) +# Find dependencies (handled by Conan) find_package(spdlog REQUIRED) +find_package(GTest REQUIRED) +find_package(Boost REQUIRED COMPONENTS system) -include(CTest) - -#-- spectator_test test executable -file(GLOB spectator_test_source_files - "spectator/*_test.cc" - "spectator/test_*.cc" - "spectator/test_*.h" -) -add_executable(spectator_test ${spectator_test_source_files}) -target_link_libraries(spectator_test - spectator - gtest::gtest -) -add_test( - NAME spectator_test - COMMAND spectator_test - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} -) - -#-- spectator library -add_library(spectator SHARED - "spectator/logger.cc" - "spectator/publisher.cc" - "spectator/config.h" - "spectator/id.h" - "spectator/logger.h" - "spectator/measurement.h" - "spectator/meter_type.h" - "spectator/publisher.h" - "spectator/registry.h" - "spectator/stateful_meters.h" - "spectator/stateless_meters.h" - "spectator/valid_chars.inc" -) -target_link_libraries(spectator - abseil::abseil - asio::asio - Backward::Backward - fmt::fmt - spdlog::spdlog -) +# Build tests if enabled +if(BUILD_TESTS) + enable_testing() +endif() -#-- generator tools -add_executable(gen_valid_chars "tools/gen_valid_chars.cc") +# Add subdirectories +add_subdirectory(libs) +add_subdirectory(spectator) -#-- file generators, must exist where the outputs are referenced -add_custom_command( - OUTPUT "spectator/valid_chars.inc" - COMMAND "${CMAKE_BINARY_DIR}/bin/gen_valid_chars" > "${CMAKE_SOURCE_DIR}/spectator/valid_chars.inc" - DEPENDS gen_valid_chars -) diff --git a/Dockerfiles/README.md b/Dockerfiles/README.md new file mode 100644 index 0000000..43e97c5 --- /dev/null +++ b/Dockerfiles/README.md @@ -0,0 +1,32 @@ +# Docker Build :hammer_and_wrench: + +The `spectator-cpp` project also supports a platform-agnostic build. The only prerequisite is the +installation of `Docker`. Once `Docker` is installed, you can build the project by running the +following commands from the root directory of the project. + +## Linux & Mac :penguin: + +##### Warning: + +- Do not prepend the command with `sudo` on Mac +- Start `Docker` before opening terminal on Mac + +```shell +sudo docker build -t spectator-cpp-image -f Dockerfiles/Ubuntu.Dockerfile . +sudo docker run -it spectatord-cpp-image +./build.sh +``` + +## Windows + +##### Warning: + +- Start `Docker` before opening `Powershell` + +```shell +docker build -t spectatord-cpp-image -f Dockerfiles/Ubuntu.Dockerfile . +docker run -it spectatord-cpp-image +apt-get install dos2unix +dos2unix build.sh +./build.sh +``` \ No newline at end of file diff --git a/Dockerfiles/Ubuntu.Dockerfile b/Dockerfiles/Ubuntu.Dockerfile new file mode 100644 index 0000000..8d957a9 --- /dev/null +++ b/Dockerfiles/Ubuntu.Dockerfile @@ -0,0 +1,25 @@ +# Use the official Ubuntu base image from Docker Hub +FROM ubuntu:latest + +# Add a few required packages for building and developer tools +RUN apt-get update && apt-get install -y \ + vim \ + git \ + python3 \ + python3-venv \ + gcc-13\ + g++-13 \ + cmake + +# Create a default working directory +WORKDIR /home/ubuntu/spectator-cpp + +# Copy all files & folders in the projects root directory +# Exclude files listed in the dockerignore file +COPY ../ /home/ubuntu/spectator-cpp + +# Setup Python virtual environment using the existing script +RUN chmod +x setup-venv.sh && ./setup-venv.sh + +# When container starts, activate the virtual environment +ENTRYPOINT ["/bin/bash", "-c", "source venv/bin/activate && exec /bin/bash"] \ No newline at end of file diff --git a/Dockerfiles/Ubuntu.Dockerfile.dockerignore b/Dockerfiles/Ubuntu.Dockerfile.dockerignore new file mode 100644 index 0000000..462844a --- /dev/null +++ b/Dockerfiles/Ubuntu.Dockerfile.dockerignore @@ -0,0 +1,2 @@ +# Ignore copying the default build folder if it exists +cmake-build/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index 7f8ced0..4841759 100644 --- a/LICENSE +++ b/LICENSE @@ -199,4 +199,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. + limitations under the License. \ No newline at end of file diff --git a/OSSMETADATA b/OSSMETADATA index b96d4a4..6c7e106 100644 --- a/OSSMETADATA +++ b/OSSMETADATA @@ -1 +1 @@ -osslifecycle=active +osslifecycle=active \ No newline at end of file diff --git a/README.md b/README.md index 748636c..d5d3791 100644 --- a/README.md +++ b/README.md @@ -8,72 +8,7 @@ consists of a thin client designed to send metrics through [spectatord](https:// ## Instrumenting Code ```C++ -#include -// use default values -static constexpr auto kDefault = 0; - -struct Request { - std::string country; -}; - -struct Response { - int status; - int size; -}; - -class Server { - public: - explicit Server(spectator::Registry* registry) - : registry_{registry}, - request_count_id_{registry->CreateId("server.requestCount", spectator::Tags{})}, - request_latency_{registry->GetTimer("server.requestLatency")}, - response_size_{registry->GetDistributionSummary("server.responseSizes")} {} - - Response Handle(const Request& request) { - auto start = std::chrono::steady_clock::now(); - - // do some work and obtain a response... - Response res{200, 64}; - - // Update the Counter id with dimensions, based on information in the request. The Counter - // will be looked up in the Registry, which is a fairly cheap operation, about the same as - // the lookup of an id object in a map. However, it is more expensive than having a local - // variable set to the Counter. - auto cnt_id = request_count_id_ - ->WithTag("country", request.country) - ->WithTag("status", std::to_string(res.status)); - registry_->GetCounter(std::move(cnt_id))->Increment(); - request_latency_->Record(std::chrono::steady_clock::now() - start); - response_size_->Record(res.size); - return res; - } - - private: - spectator::Registry* registry_; - std::shared_ptr request_count_id_; - std::shared_ptr request_latency_; - std::shared_ptr response_size_; -}; - -Request get_next_request() { - return Request{"US"}; -} - -int main() { - auto logger = spdlog::stdout_color_mt("console"); - std::unordered_map common_tags{{"xatlas.process", "some-sidecar"}}; - spectator::Config cfg{"unix:/run/spectatord/spectatord.unix", common_tags}; - spectator::Registry registry{std::move(cfg), logger); - - Server server{®istry}; - - for (auto i = 1; i <= 3; ++i) { - // get a request - auto req = get_next_request(); - server.Handle(req); - } -} ``` ## High-Volume Publishing @@ -106,4 +41,4 @@ source venv/bin/activate * Open the project. The wizard will show three CMake profiles. * Disable the default Cmake `Debug` profile. * Enable the CMake `conan-debug` profile. - * CLion > View > Tool Windows > Conan > (gear) > Conan Executable: `$PROJECT_HOME/venv/bin/conan` + * CLion > View > Tool Windows > Conan > (gear) > Conan Executable: `$PROJECT_HOME/venv/bin/conan` \ No newline at end of file diff --git a/build.sh b/build.sh index 5dd1479..03ce752 100755 --- a/build.sh +++ b/build.sh @@ -19,7 +19,7 @@ NC="\033[0m" if [[ "$1" == "clean" ]]; then echo -e "${BLUE}==== clean ====${NC}" rm -rf "$BUILD_DIR" - rm -f spectator/*.inc + rm -rf lib/spectator if [[ "$2" == "--confirm" ]]; then # remove all packages from the conan cache, to allow swapping between Release/Debug builds conan remove "*" --confirm @@ -27,18 +27,13 @@ if [[ "$1" == "clean" ]]; then fi if [[ "$OSTYPE" == "linux-gnu"* ]]; then - if [[ -z "$CC" || -z "$CXX" ]]; then - export CC=gcc-13 - export CXX=g++-13 + source /etc/os-release + if [[ "$NAME" == "Ubuntu" ]]; then + if [[ -z "$CC" ]]; then export CC=gcc-13; fi + if [[ -z "$CXX" ]]; then export CXX=g++-13; fi fi fi -echo -e "${BLUE}==== env configuration ====${NC}" -echo "BUILD_DIR=$BUILD_DIR" -echo "BUILD_TYPE=$BUILD_TYPE" -echo "CC=$CC" -echo "CXX=$CXX" - if [[ ! -f "$HOME/.conan2/profiles/default" ]]; then echo -e "${BLUE}==== create default profile ====${NC}" conan profile detect @@ -47,13 +42,16 @@ fi if [[ ! -d $BUILD_DIR ]]; then echo -e "${BLUE}==== install required dependencies ====${NC}" if [[ "$BUILD_TYPE" == "Debug" ]]; then - conan install . --output-folder="$BUILD_DIR" --build="*" --settings=build_type="$BUILD_TYPE" --profile=./sanitized + conan install . --output-folder="$BUILD_DIR" --build="*" --settings=build_type="$BUILD_TYPE" else - conan install . --output-folder="$BUILD_DIR" --build=missing --settings=build_type="$BUILD_TYPE" + conan install . --output-folder="$BUILD_DIR" --build=missing fi + + echo -e "${BLUE}==== install source dependencies ====${NC}" + conan source . fi -pushd $BUILD_DIR +pushd "$BUILD_DIR" echo -e "${BLUE}==== configure conan environment to access tools ====${NC}" source conanbuild.sh @@ -63,7 +61,7 @@ if [[ $OSTYPE == "darwin"* ]]; then fi echo -e "${BLUE}==== generate build files ====${NC}" -cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE +cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE="$BUILD_TYPE" echo -e "${BLUE}==== build ====${NC}" cmake --build . @@ -73,4 +71,4 @@ if [[ "$1" != "skiptest" ]]; then GTEST_COLOR=1 ctest --verbose fi -popd +popd \ No newline at end of file diff --git a/conanfile.py b/conanfile.py index a975f22..ada0578 100644 --- a/conanfile.py +++ b/conanfile.py @@ -4,12 +4,9 @@ class SpectatorCppConan(ConanFile): settings = "os", "compiler", "build_type", "arch" requires = ( - "abseil/20240116.2", - "asio/1.32.0", - "backward-cpp/1.6", - "fmt/11.0.2", - "gtest/1.15.0", "spdlog/1.15.0", + "gtest/1.14.0", + "boost/1.83.0", ) tool_requires = () generators = "CMakeDeps", "CMakeToolchain" diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt new file mode 100644 index 0000000..a289f84 --- /dev/null +++ b/libs/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(config) +add_subdirectory(logger) +add_subdirectory(meter) +add_subdirectory(utils) +add_subdirectory(writer) \ No newline at end of file diff --git a/libs/README.md b/libs/README.md new file mode 100644 index 0000000..478e9be --- /dev/null +++ b/libs/README.md @@ -0,0 +1,21 @@ +# Spectator-CPP Libraries + +This directory contains all the core libraries that make up the Spectator-CPP framework. These modular components work together to build the implementation of the main Spectator Registry interface. + +## Library Overview + +| Library | Description | +|---------|-------------| +| `config` | Configuration handling for the Spectator Registry metrics including output location and tags | +| `logger` | Logging facilities used throughout the framework | +| `meter` | Core metrics implementations including counters, gauges, timers, and meter identification | +| `utils` | Utility classes and helpers including singleton patterns | +| `writer` | Output writers for metrics data (file, memory, UDP, Unix Domain Socket) | + +## Usage + +Each library subfolder contains additional documentation describing its specific API and usage examples. See the main project README for complete integration instructions. + +## Dependencies + +Most libraries have minimal external dependencies, though some writers may require specific system capabilities for networking. \ No newline at end of file diff --git a/libs/config/CMakeLists.txt b/libs/config/CMakeLists.txt new file mode 100644 index 0000000..87d5bba --- /dev/null +++ b/libs/config/CMakeLists.txt @@ -0,0 +1,24 @@ +add_library(spectator-config + src/config.cpp +) + +target_include_directories(spectator-config + PUBLIC ${CMAKE_SOURCE_DIR} +) + +add_executable(config-tests + test/test_config.cpp +) + +target_link_libraries(config-tests PRIVATE + spectator-config + GTest::gtest + GTest::gtest_main + spectator-writer-config +) + +add_test( + NAME config-tests + COMMAND config-tests + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} +) diff --git a/libs/config/README.md b/libs/config/README.md new file mode 100644 index 0000000..db69325 --- /dev/null +++ b/libs/config/README.md @@ -0,0 +1,69 @@ +# Config Library + +## Overview + +The `Config` class serves as the configuration object for the Registry class, which manages metrics for the spectatorD system. It defines how and where metrics are written and what additional tags are applied to them. + +## Usage + +The `Config` class provides two constructors: + +```cpp +// Constructor 1: Specify output location as string +Config(const std::string &location = "udp", + const std::unordered_map &extra_tags = {}); + +// Constructor 2: Specify writer type directly (recommended) +Config(WriterType type, + const std::unordered_map &extra_tags = {}); + +// Examples: + +// Example 1: Create a default config (UDP output) +auto defaultConfig = Config(); + +// Example 2: Config with memory storage and custom tags +auto memoryConfig = Config("memory", { + {"app", "myService"}, + {"zone", "us-west-2"} +}); + +// Example 3: Config with direct writer type +auto stdoutConfig = Config(WriterTypes::Memory, { + {"env", "production"} +}); + +// Example 4: Config writing to a specific file +auto fileConfig = Config("file:///var/log/metrics.log"); + +// Example 5: Config sending to specific UDP endpoint +auto customUdpConfig = Config("udp://metrics-collector.example.com:8125"); +``` + +### When to Use Each Constructor + +- Use the first constructor when you need to specify a custom output location. +- Use the second constructor (preferred) when working with standard writer types. + +### Output Locations + +Valid output locations include: +- `none`: Disable output +- `memory`: Store metrics in memory +- `stdout`: Write to standard output +- `stderr`: Write to standard error +- `udp`: Send metrics over UDP (default) +- `unix`: Use Unix domain sockets +- `file://path`: Write to a file +- `udp://host:port`: Send to specific UDP endpoint +- `unix://path`: Use specific Unix socket + +### Environment Variables + +- `SPECTATOR_OUTPUT_LOCATION`: Override the configured output location +- `TITUS_CONTAINER_NAME`: Set the `nf.container` tag automatically +- `TITUS_PROCESS_NAME`: Set the `nf.process` tag automatically + +## Extra Tags + +Extra tags are additional key-value pairs attached to all metrics. They can be specified during initialization and will be merged with environment-derived tags. \ No newline at end of file diff --git a/libs/config/include/config.h b/libs/config/include/config.h new file mode 100644 index 0000000..27c5a61 --- /dev/null +++ b/libs/config/include/config.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include + +class Config +{ + public: + + Config(WriterConfig writerConfig, const std::unordered_map &extra_tags = {}); + + // Rule of 5 + ~Config() = default; // Destructor + Config(const Config &other) = default; // Copy constructor + Config &operator=(const Config &other) = delete; // Copy assignment operator + Config(Config &&other) noexcept = delete; // Move constructor + Config &operator=(Config &&other) noexcept = delete; // Move assignment operator + + const std::string &GetLocation() const { return m_writerConfig.GetLocation(); } + + const std::unordered_map &GetExtraTags() const{ return m_extraTags;} + + const WriterType &GetWriterType() const { return m_writerConfig.GetType();} + + private: + std::unordered_map CalculateTags(const std::unordered_map &tags); + + std::unordered_map m_extraTags; + WriterConfig m_writerConfig; +}; \ No newline at end of file diff --git a/libs/config/src/config.cpp b/libs/config/src/config.cpp new file mode 100644 index 0000000..964562f --- /dev/null +++ b/libs/config/src/config.cpp @@ -0,0 +1,39 @@ +#include + +struct ConfigConstants +{ + static constexpr auto container = "nf.container"; + static constexpr auto process = "nf.process"; + static constexpr auto envVarContainer = "TITUS_CONTAINER_NAME"; + static constexpr auto envVarProcess = "TITUS_PROCESS_NAME"; +}; + +Config::Config(WriterConfig writerConfig, const std::unordered_map &extra_tags) + : m_extraTags(CalculateTags(extra_tags)), m_writerConfig(writerConfig) {} + +std::unordered_map Config::CalculateTags(const std::unordered_map &tags) +{ + std::unordered_map valid_tags; + + const char *container_name = std::getenv(ConfigConstants::envVarContainer); + const char *process_name = std::getenv(ConfigConstants::envVarProcess); + if (container_name) + { + valid_tags[ConfigConstants::container] = container_name; + } + + if (process_name) + { + valid_tags[ConfigConstants::process] = process_name; + } + + for (const auto &kv : tags) + { + if (!kv.first.empty() && !kv.second.empty()) + { + valid_tags[kv.first] = kv.second; + } + } + + return valid_tags; +} diff --git a/libs/config/test/test_config.cpp b/libs/config/test/test_config.cpp new file mode 100644 index 0000000..2f1f221 --- /dev/null +++ b/libs/config/test/test_config.cpp @@ -0,0 +1,209 @@ +#include +#include + +#include + +// Helper to temporarily set an environment variable for testing +class EnvVarSetter +{ + public: + EnvVarSetter(const std::string &name, const std::string &value) : m_name(name) + { + // Store original value (might be nullptr) + m_originalValue = std::getenv(name.c_str()); + + // Set the new value + setenv(name.c_str(), value.c_str(), 1); + } + + ~EnvVarSetter() + { + // Restore original state + if (m_originalValue) + setenv(m_name.c_str(), m_originalValue, 1); + else + unsetenv(m_name.c_str()); + } + + private: + std::string m_name; + const char *m_originalValue; +}; + +// Helper to temporarily unset an environment variable +class EnvVarUnset +{ + public: + EnvVarUnset(const std::string &name) : m_name(name) + { + // Store original value (might be nullptr) + m_originalValue = std::getenv(name.c_str()); + + // Always unset regardless of whether it was set before + unsetenv(name.c_str()); + } + + ~EnvVarUnset() + { + // Only restore if there was an original value + if (m_originalValue) + setenv(m_name.c_str(), m_originalValue, 1); + } + + private: + std::string m_name; + const char *m_originalValue; +}; + +class ConfigTest : public ::testing::Test +{ + protected: + void SetUp() override + { + // Ensure environment variables are unset before each test + unsetenv("TITUS_CONTAINER_NAME"); + unsetenv("TITUS_PROCESS_NAME"); + } +}; + +// Test initialization with different writer configs +TEST_F(ConfigTest, WriterConfigInitialization) +{ + // Test with memory writer + { + WriterConfig writerConfig(WriterTypes::Memory); + Config config(writerConfig); + + EXPECT_EQ(config.GetLocation(), ""); + EXPECT_EQ(config.GetWriterType(), WriterType::Memory); + EXPECT_TRUE(config.GetExtraTags().empty()); + } + + // Test with UDP writer + { + WriterConfig writerConfig(WriterTypes::UDP); + Config config(writerConfig); + + EXPECT_EQ(config.GetLocation(), DefaultLocations::UDP); + EXPECT_EQ(config.GetWriterType(), WriterType::UDP); + } +} + +// Test extra tags handling +TEST_F(ConfigTest, ExtraTags) +{ + WriterConfig writerConfig(WriterTypes::Memory); + + // Empty tags + { + Config config(writerConfig, {}); + EXPECT_TRUE(config.GetExtraTags().empty()); + } + + // Valid tags + { + std::unordered_map tags = {{"app", "test-app"}, {"env", "testing"}, {"region", "us-east-1"}}; + + Config config(writerConfig, tags); + + EXPECT_EQ(config.GetExtraTags().size(), 3); + EXPECT_EQ(config.GetExtraTags().at("app"), "test-app"); + EXPECT_EQ(config.GetExtraTags().at("env"), "testing"); + EXPECT_EQ(config.GetExtraTags().at("region"), "us-east-1"); + } + + // Invalid tags (empty keys or values should be ignored) + { + std::unordered_map tags = {{"valid", "value"}, {"", "empty-key"}, {"empty-value", ""}}; + + Config config(writerConfig, tags); + + EXPECT_EQ(config.GetExtraTags().size(), 1); + EXPECT_EQ(config.GetExtraTags().at("valid"), "value"); + EXPECT_FALSE(config.GetExtraTags().count("")); + EXPECT_FALSE(config.GetExtraTags().count("empty-value")); + } +} + +// Test environment variable integration +TEST_F(ConfigTest, EnvironmentVariables) +{ + WriterConfig writerConfig(WriterTypes::Memory); + + // No environment variables + { + EnvVarUnset container("TITUS_CONTAINER_NAME"); + EnvVarUnset process("TITUS_PROCESS_NAME"); + + Config config(writerConfig); + EXPECT_TRUE(config.GetExtraTags().empty()); + } + + // With container name + { + EnvVarSetter container("TITUS_CONTAINER_NAME", "test-container"); + EnvVarUnset process("TITUS_PROCESS_NAME"); + + Config config(writerConfig); + + EXPECT_EQ(config.GetExtraTags().size(), 1); + EXPECT_EQ(config.GetExtraTags().at("nf.container"), "test-container"); + } + + // With process name + { + EnvVarUnset container("TITUS_CONTAINER_NAME"); + EnvVarSetter process("TITUS_PROCESS_NAME", "test-process"); + + Config config(writerConfig); + + EXPECT_EQ(config.GetExtraTags().size(), 1); + EXPECT_EQ(config.GetExtraTags().at("nf.process"), "test-process"); + } + + // With both environment variables + { + EnvVarSetter container("TITUS_CONTAINER_NAME", "test-container"); + EnvVarSetter process("TITUS_PROCESS_NAME", "test-process"); + + Config config(writerConfig); + + EXPECT_EQ(config.GetExtraTags().size(), 2); + EXPECT_EQ(config.GetExtraTags().at("nf.container"), "test-container"); + EXPECT_EQ(config.GetExtraTags().at("nf.process"), "test-process"); + } +} + +// Test merging of environment variables and explicit tags +TEST_F(ConfigTest, MergingTags) +{ + WriterConfig writerConfig(WriterTypes::Memory); + + // Environment variables with additional tags + { + EnvVarSetter container("TITUS_CONTAINER_NAME", "test-container"); + EnvVarSetter process("TITUS_PROCESS_NAME", "test-process"); + + std::unordered_map tags = {{"custom", "value"}, {"env", "test"}}; + + Config config(writerConfig, tags); + + EXPECT_EQ(config.GetExtraTags().size(), 4); + EXPECT_EQ(config.GetExtraTags().at("nf.container"), "test-container"); + EXPECT_EQ(config.GetExtraTags().at("nf.process"), "test-process"); + EXPECT_EQ(config.GetExtraTags().at("custom"), "value"); + EXPECT_EQ(config.GetExtraTags().at("env"), "test"); + } + + // Override environment variables with explicit tags + { + EnvVarSetter container("TITUS_CONTAINER_NAME", "test-container"); + + std::unordered_map tags = {{"nf.container", "override-container"}}; + + Config config(writerConfig, tags); + + EXPECT_EQ(config.GetExtraTags().size(), 1); + EXPECT_EQ(config.GetExtraTags().at("nf.container"), "override-container"); + } +} diff --git a/libs/logger/CMakeLists.txt b/libs/logger/CMakeLists.txt new file mode 100644 index 0000000..4d73d98 --- /dev/null +++ b/libs/logger/CMakeLists.txt @@ -0,0 +1,12 @@ +add_library(spectator-logger INTERFACE) + +target_include_directories(spectator-logger + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(spectator-logger + INTERFACE + spectator-utils + spdlog::spdlog +) \ No newline at end of file diff --git a/libs/logger/logger.h b/libs/logger/logger.h new file mode 100644 index 0000000..36ff640 --- /dev/null +++ b/libs/logger/logger.h @@ -0,0 +1,93 @@ +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include +#include + +constexpr const char *kMainLogger = "spectator"; + +class Logger final : public Singleton +{ + private: + spdlog::logger *m_logger; // Use raw pointer, not unique_ptr + + friend class Singleton; + + Logger() + { + try + { + spdlog::init_thread_pool(8192, 1); + auto sink = std::make_shared(); + auto shared_logger = + std::make_shared(kMainLogger, sink, spdlog::thread_pool(), spdlog::async_overflow_policy::block); + shared_logger->set_level(spdlog::level::debug); + spdlog::register_logger(shared_logger); + m_logger = shared_logger.get(); + } + catch (const spdlog::spdlog_ex &ex) + { + std::cerr << "Log initialization failed: " << ex.what() << "\n"; + m_logger = nullptr; + } + } + + ~Logger() = default; + Logger(const Logger &) = delete; + Logger &operator=(const Logger &) = delete; + Logger(Logger &&) = delete; + Logger &operator=(Logger &&) = delete; + + public: + static spdlog::logger *GetLogger() + { + return GetInstance().m_logger; + } + + static void debug(const std::string &msg) + { + GetLogger()->debug(msg); + } + + static void info(const std::string &msg) + { + GetLogger()->info(msg); + } + + static void warn(const std::string &msg) + { + GetLogger()->warn(msg); + } + + static void error(const std::string &msg) + { + GetLogger()->error(msg); + } + + template static void debug(fmt::format_string fmt, Args &&...args) + { + GetLogger()->debug(fmt, std::forward(args)...); + } + + template static void info(fmt::format_string fmt, Args &&...args) + { + GetLogger()->info(fmt, std::forward(args)...); + } + + template static void warn(fmt::format_string fmt, Args &&...args) + { + GetLogger()->warn(fmt, std::forward(args)...); + } + + template static void error(fmt::format_string fmt, Args &&...args) + { + GetLogger()->error(fmt, std::forward(args)...); + } +}; \ No newline at end of file diff --git a/libs/meter/CMakeLists.txt b/libs/meter/CMakeLists.txt new file mode 100644 index 0000000..8d6af59 --- /dev/null +++ b/libs/meter/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(meter_id) +add_subdirectory(meter_types) \ No newline at end of file diff --git a/libs/meter/meter_id/CMakeLists.txt b/libs/meter/meter_id/CMakeLists.txt new file mode 100644 index 0000000..255cd06 --- /dev/null +++ b/libs/meter/meter_id/CMakeLists.txt @@ -0,0 +1,18 @@ +add_library(spectator-meter-id + src/meter_id.cpp +) + +target_include_directories(spectator-meter-id + PUBLIC + ${CMAKE_SOURCE_DIR} +) + +add_executable(MeterID-test + test/test_meter_id.cpp +) + +target_link_libraries(MeterID-test PRIVATE + GTest::gtest + GTest::gtest_main + spectator-meter-id +) \ No newline at end of file diff --git a/libs/meter/meter_id/include/meter_id.h b/libs/meter/meter_id/include/meter_id.h new file mode 100644 index 0000000..c8f4fbf --- /dev/null +++ b/libs/meter/meter_id/include/meter_id.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include +#include + +class MeterId +{ + public: + MeterId(const std::string &name, const std::unordered_map &tags = {}); + + const std::string &GetName() const noexcept { return m_name; }; + + const std::unordered_map &GetTags() const noexcept { return m_tags; }; + + MeterId WithTag(const std::string &key, const std::string &value) const; + + MeterId WithTags(const std::unordered_map &additional_tags) const; + + std::string spectatord_id; + + bool operator==(const MeterId &other) const; + + std::string to_string() const; + + std::string GetSpectatordId() const + { + return ToSpectatorId(m_name, m_tags); + } + + private: + std::string RepleaceInvalidChars(const std::string &s) const; + std::string ToSpectatorId(const std::string &name, const std::unordered_map &tags) const; + + static const std::regex INVALID_CHARS; + std::string m_name; + std::unordered_map m_tags; +}; + +namespace std +{ +template <> struct hash +{ + size_t operator()(const MeterId &id) const; +}; +} // namespace std \ No newline at end of file diff --git a/libs/meter/meter_id/src/meter_id.cpp b/libs/meter/meter_id/src/meter_id.cpp new file mode 100644 index 0000000..cfec332 --- /dev/null +++ b/libs/meter/meter_id/src/meter_id.cpp @@ -0,0 +1,108 @@ +#include + +#include +#include + +// Define the static member +const std::regex MeterId::INVALID_CHARS("[^-._A-Za-z0-9~^]"); + +std::unordered_map ValidateTags(const std::unordered_map &tags) +{ + std::unordered_map validTags{}; + + for (const auto &[key, value] : tags) + { + if (key.empty() == false && value.empty() == false) + { + validTags[key] = value; + } + } + + return validTags; +} + +MeterId::MeterId(const std::string &name, const std::unordered_map &tags) + : m_name(name), m_tags(ValidateTags(tags)) +{ + spectatord_id = ToSpectatorId(m_name, m_tags); +} + +MeterId MeterId::WithTag(const std::string &key, const std::string &value) const +{ + auto new_tags = m_tags; + new_tags[key] = value; + return MeterId(m_name, new_tags); +} + +MeterId MeterId::WithTags(const std::unordered_map &additional_tags) const +{ + auto new_tags = m_tags; + for (const auto &pair : additional_tags) + { + new_tags[pair.first] = pair.second; + } + return MeterId(m_name, new_tags); +} + +bool MeterId::operator==(const MeterId &other) const +{ + return m_name == other.m_name && m_tags == other.m_tags; +} + +std::string MeterId::to_string() const +{ + std::ostringstream ss; + ss << "MeterId(name=" << m_name << ", tags={"; + bool first = true; + for (const auto &pair : m_tags) + { + if (!first) + { + ss << ", "; + } + ss << "'" << pair.first << "': '" << pair.second << "'"; + first = false; + } + ss << "})"; + return ss.str(); +} + +std::string MeterId::RepleaceInvalidChars(const std::string &s) const +{ + return std::regex_replace(s, INVALID_CHARS, "_"); +} + +std::string MeterId::ToSpectatorId(const std::string &name, const std::unordered_map &tags) const +{ + std::ostringstream ss; + ss << RepleaceInvalidChars(name); + if (!tags.empty()) + { + for (const auto &tag : tags) + { + ss << "," << RepleaceInvalidChars(tag.first) << "=" << RepleaceInvalidChars(tag.second); + } + } + return ss.str(); +} + +// Implementation of the hash function for MeterId +size_t std::hash::operator()(const MeterId &id) const +{ + // Hash the name first + size_t name_hash = std::hash{}(id.GetName()); + + // Hash the tags + size_t tags_hash = 0; + for (const auto &tag : id.GetTags()) + { + // Combine key and value hashes + size_t pair_hash = std::hash{}(tag.first) ^ (std::hash{}(tag.second) << 1); + // Combine with the accumulated tags hash + tags_hash ^= pair_hash + 0x9e3779b9 + (tags_hash << 6) + (tags_hash >> 2); + } + + // Combine name hash and tags hash + return name_hash ^ (tags_hash << 1); +} + diff --git a/libs/meter/meter_id/test/test_meter_id.cpp b/libs/meter/meter_id/test/test_meter_id.cpp new file mode 100644 index 0000000..9638ea4 --- /dev/null +++ b/libs/meter/meter_id/test/test_meter_id.cpp @@ -0,0 +1,109 @@ +#include + +#include + +TEST(MeterIdTest, EqualsSameName) +{ + MeterId id1("foo"); + MeterId id2("foo"); + EXPECT_EQ(id1, id2); +} + +TEST(MeterIdTest, EqualsSameTags) +{ + MeterId id1("foo", {{"a", "1"}, {"b", "2"}, {"c", "3"}}); + MeterId id2("foo", {{"c", "3"}, {"b", "2"}, {"a", "1"}}); + EXPECT_EQ(id1, id2); +} + +TEST(MeterIdTest, HashSameTags) +{ + MeterId id1("foo", {{"a", "1"}, {"b", "2"}, {"c", "3"}}); + MeterId id2("foo", {{"c", "3"}, {"b", "2"}, {"a", "1"}}); + EXPECT_EQ(std::hash{}(id1), std::hash{}(id2)); +} + +TEST(MeterIdTest, IllegalCharsAreReplaced) +{ + MeterId id("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo"); + EXPECT_EQ("test______^____-_~______________.___foo", id.GetSpectatordId()); +} + +TEST(MeterIdTest, LookupTags) +{ + MeterId id1("foo", {{"a", "1"}, {"b", "2"}, {"c", "3"}}); + MeterId id2("foo", {{"c", "3"}, {"b", "2"}, {"a", "1"}}); + std::unordered_map d; + d[id1] = "test"; + EXPECT_EQ("test", d[id2]); +} + +TEST(MeterIdTest, Name) +{ + MeterId id1("foo", {{"a", "1"}}); + EXPECT_EQ("foo", id1.GetName()); +} + +TEST(MeterIdTest, SpectatordId) +{ + MeterId id1("foo"); + EXPECT_EQ("foo", id1.GetSpectatordId()); + + MeterId id2("bar", {{"a", "1"}}); + EXPECT_EQ("bar,a=1", id2.GetSpectatordId()); + + MeterId id3("baz", {{"a", "1"}, {"b", "2"}}); + EXPECT_EQ("baz,a=1,b=2", id3.GetSpectatordId()); +} + +TEST(MeterIdTest, ToString) +{ + MeterId id1("foo"); + EXPECT_EQ("MeterId(name=foo, tags={})", id1.to_string()); + + MeterId id2("bar", {{"a", "1"}}); + EXPECT_EQ("MeterId(name=bar, tags={'a': '1'})", id2.to_string()); + + MeterId id3("baz", {{"a", "1"}, {"b", "2"}, {"c", "3"}}); + EXPECT_EQ("MeterId(name=baz, tags={'a': '1', 'b': '2', 'c': '3'})", id3.to_string()); +} + +TEST(MeterIdTest, Tags) +{ + MeterId id1("foo", {{"a", "1"}}); + std::unordered_map expected = {{"a", "1"}}; + EXPECT_EQ(expected, id1.GetTags()); +} + +TEST(MeterIdTest, TagsDefensiveCopy) +{ + MeterId id1("foo", {{"a", "1"}}); + auto tags = id1.GetTags(); + tags["b"] = "2"; + std::unordered_map expected = {{"a", "1"}, {"b", "2"}}; + EXPECT_EQ(expected, tags); + std::unordered_map expected_original = {{"a", "1"}}; + EXPECT_EQ(expected_original, id1.GetTags()); +} + +TEST(MeterIdTest, WithTagReturnsNewObject) +{ + MeterId id1("foo"); + MeterId id2 = id1.WithTag("a", "1"); + EXPECT_NE(id1, id2); + std::unordered_map empty; + EXPECT_EQ(empty, id1.GetTags()); + std::unordered_map expected = {{"a", "1"}}; + EXPECT_EQ(expected, id2.GetTags()); +} + +TEST(MeterIdTest, WithTagsReturnsNewObject) +{ + MeterId id1("foo"); + MeterId id2 = id1.WithTags({{"a", "1"}, {"b", "2"}}); + EXPECT_NE(id1, id2); + std::unordered_map empty; + EXPECT_EQ(empty, id1.GetTags()); + std::unordered_map expected = {{"a", "1"}, {"b", "2"}}; + EXPECT_EQ(expected, id2.GetTags()); +} \ No newline at end of file diff --git a/libs/meter/meter_types/CMakeLists.txt b/libs/meter/meter_types/CMakeLists.txt new file mode 100644 index 0000000..77dbc9f --- /dev/null +++ b/libs/meter/meter_types/CMakeLists.txt @@ -0,0 +1,41 @@ +add_library(spectator-meter-types INTERFACE) + +target_include_directories(spectator-meter-types + INTERFACE + ${CMAKE_SOURCE_DIR} +) + +# List all the test files +set(TEST_SOURCES + test/test_age_gauge.cpp + test/test_counter.cpp + test/test_dist_summary.cpp + test/test_gauge.cpp + test/test_max_gauge.cpp + test/test_monotonic_counter.cpp + test/test_monotonic_counter_uint.cpp + test/test_percentile_dist_summary.cpp + test/test_percentile_timer.cpp + test/test_timer.cpp +) + +# Create individual test executables for each test file +foreach(test_file ${TEST_SOURCES}) + # Get the filename without extension and path + get_filename_component(test_name ${test_file} NAME_WE) + + # Create an executable for this test file + add_executable(${test_name} ${test_file}) + + # Link against GTest and other required libraries + target_link_libraries(${test_name} PRIVATE + GTest::GTest + GTest::Main + spectator-meter-types + spectator-meter-id + spectator-writer-wrapper + ) + + # Add the test to CTest + add_test(NAME ${test_name} COMMAND ${test_name}) +endforeach() \ No newline at end of file diff --git a/libs/meter/meter_types/include/age_gauge.h b/libs/meter/meter_types/include/age_gauge.h new file mode 100644 index 0000000..fc478ae --- /dev/null +++ b/libs/meter/meter_types/include/age_gauge.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +#include + +static constexpr auto AGE_GAUGE_TYPE_SYMBOL = "A"; + +class AgeGauge final : public Meter +{ + public: + explicit AgeGauge(const MeterId &meter_id) : Meter(meter_id, AGE_GAUGE_TYPE_SYMBOL) + { + } + + void Now() + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + "0"; + Writer::GetInstance().Write(line); + } + + void Set(const int &seconds) + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(seconds); + Writer::GetInstance().Write(line); + } +}; diff --git a/libs/meter/meter_types/include/base/meter.h b/libs/meter/meter_types/include/base/meter.h new file mode 100644 index 0000000..4401d74 --- /dev/null +++ b/libs/meter/meter_types/include/base/meter.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +class Meter +{ + public: + static constexpr auto FIELD_SEPARATOR = ":"; + + Meter(const MeterId &meter_id, const std::string &meter_type_symbol) : m_id(meter_id), m_meterTypeSymbol(meter_type_symbol) + { + } + virtual ~Meter() = default; + + const MeterId &GetId() const noexcept + { + return m_id; + } + + const std::string &GetMeterTypeSymbol() const noexcept + { + return m_meterTypeSymbol; + } + + protected: + MeterId m_id; + std::string m_meterTypeSymbol; +}; diff --git a/libs/meter/meter_types/include/counter.h b/libs/meter/meter_types/include/counter.h new file mode 100644 index 0000000..cec6209 --- /dev/null +++ b/libs/meter/meter_types/include/counter.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +#include + +static constexpr auto COUNTER_TYPE_SYMBOL = "c"; + +class Counter final : public Meter +{ + public: + explicit Counter(const MeterId &meter_id) : Meter(meter_id, COUNTER_TYPE_SYMBOL) + { + } + + void Increment(const double &delta = 1) + { + if (delta > 0) + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(delta); + Writer::GetInstance().Write(line); + } + } +}; diff --git a/libs/meter/meter_types/include/dist_summary.h b/libs/meter/meter_types/include/dist_summary.h new file mode 100644 index 0000000..05fd5a2 --- /dev/null +++ b/libs/meter/meter_types/include/dist_summary.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +#include + +static constexpr auto DisTRIBUTION_SUMMARY_TYPE_SYMBOL = "d"; + +class DistributionSummary final : public Meter +{ + public: + explicit DistributionSummary(const MeterId &meter_id) : Meter(meter_id, DisTRIBUTION_SUMMARY_TYPE_SYMBOL) + { + } + + void Record(const int &amount) + { + if (amount >= 0) + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(amount); + Writer::GetInstance().Write(line); + } + } +}; \ No newline at end of file diff --git a/libs/meter/meter_types/include/gauge.h b/libs/meter/meter_types/include/gauge.h new file mode 100644 index 0000000..d29a96c --- /dev/null +++ b/libs/meter/meter_types/include/gauge.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +#include +#include + +static constexpr auto GAUGE_TYPE_SYMBOL = "g"; + +class Gauge final : public Meter +{ + public: + explicit Gauge(const MeterId &meter_id, const std::optional &ttl_seconds = std::nullopt) + : Meter(meter_id, + ttl_seconds.has_value() ? GAUGE_TYPE_SYMBOL + std::string(",") + std::to_string(ttl_seconds.value()) : GAUGE_TYPE_SYMBOL) + { + } + + void Set(const double &value) + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(value); + Writer::GetInstance().Write(line); + } +}; \ No newline at end of file diff --git a/libs/meter/meter_types/include/max_gauge.h b/libs/meter/meter_types/include/max_gauge.h new file mode 100644 index 0000000..5d84319 --- /dev/null +++ b/libs/meter/meter_types/include/max_gauge.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +#include + +static constexpr auto MAX_GAUGE_TYPE_SYMBOL = "m"; + +class MaxGauge final : public Meter +{ + public: + explicit MaxGauge(const MeterId &meter_id) : Meter(meter_id, MAX_GAUGE_TYPE_SYMBOL) + { + } + + void Set(const double &value) + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(value); + Writer::GetInstance().Write(line); + } +}; \ No newline at end of file diff --git a/libs/meter/meter_types/include/meter_types.h b/libs/meter/meter_types/include/meter_types.h new file mode 100644 index 0000000..6689c90 --- /dev/null +++ b/libs/meter/meter_types/include/meter_types.h @@ -0,0 +1,15 @@ +#pragma once + +// Umbrella header for all meter types + +// Individual meter type headers +#include "age_gauge.h" +#include "counter.h" +#include "dist_summary.h" +#include "gauge.h" +#include "max_gauge.h" +#include "monotonic_counter.h" +#include "monotonic_counter_uint.h" +#include "percentile_dist_summary.h" +#include "percentile_timer.h" +#include "timer.h" diff --git a/libs/meter/meter_types/include/monotonic_counter.h b/libs/meter/meter_types/include/monotonic_counter.h new file mode 100644 index 0000000..86a12a9 --- /dev/null +++ b/libs/meter/meter_types/include/monotonic_counter.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +#include + +static constexpr auto MONOTONIC_COUNTER_TYPE_SYMBOL = "C"; + +class MonotonicCounter final : public Meter +{ + public: + explicit MonotonicCounter(const MeterId &meter_id) : Meter(meter_id, MONOTONIC_COUNTER_TYPE_SYMBOL) + { + } + + void Set(const double &amount) + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(amount); + Writer::GetInstance().Write(line); + } +}; diff --git a/libs/meter/meter_types/include/monotonic_counter_uint.h b/libs/meter/meter_types/include/monotonic_counter_uint.h new file mode 100644 index 0000000..48b51cb --- /dev/null +++ b/libs/meter/meter_types/include/monotonic_counter_uint.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include +#include + +#include + +static constexpr auto MONOTONIC_COUNTER_UINT_TYPE_SYMBOL = "U"; + +class MonotonicCounterUint final : public Meter +{ + public: + explicit MonotonicCounterUint(const MeterId &meter_id) : Meter(meter_id, MONOTONIC_COUNTER_UINT_TYPE_SYMBOL) + { + } + + void Set(const uint64_t &amount) + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(amount); + Writer::GetInstance().Write(line); + } +}; diff --git a/libs/meter/meter_types/include/percentile_dist_summary.h b/libs/meter/meter_types/include/percentile_dist_summary.h new file mode 100644 index 0000000..10147ab --- /dev/null +++ b/libs/meter/meter_types/include/percentile_dist_summary.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include + +#include + +static constexpr auto PERCENTILE_DISTRIBUTION_SUMMARY_TYPE_SYMBOL = "D"; + +class PercentileDistributionSummary final : public Meter +{ + public: + explicit PercentileDistributionSummary(const MeterId &meter_id) + : Meter(meter_id, PERCENTILE_DISTRIBUTION_SUMMARY_TYPE_SYMBOL) + { + } + + void Record(const int &amount) + { + if (amount >= 0) + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(amount); + Writer::GetInstance().Write(line); + } + } +}; diff --git a/libs/meter/meter_types/include/percentile_timer.h b/libs/meter/meter_types/include/percentile_timer.h new file mode 100644 index 0000000..379f564 --- /dev/null +++ b/libs/meter/meter_types/include/percentile_timer.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +#include + +static constexpr auto PERCENTILE_TIMER_TYPE_SYMBOL = "T"; + +class PercentileTimer final : public Meter +{ + public: + explicit PercentileTimer(const MeterId &meter_id) : Meter(meter_id, PERCENTILE_TIMER_TYPE_SYMBOL) + { + } + + void Record(const double &seconds) + { + if (seconds >= 0) + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(seconds); + Writer::GetInstance().Write(line); + } + } +}; diff --git a/libs/meter/meter_types/include/timer.h b/libs/meter/meter_types/include/timer.h new file mode 100644 index 0000000..3ae106d --- /dev/null +++ b/libs/meter/meter_types/include/timer.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +#include + +static constexpr auto TIMER_TYPE_SYMBOL = "t"; + +class Timer final : public Meter +{ + public: + explicit Timer(const MeterId &meter_id) : Meter(meter_id, TIMER_TYPE_SYMBOL) + { + } + + void Record(const double &seconds) + { + if (seconds >= 0) + { + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(seconds); + Writer::GetInstance().Write(line); + } + } +}; \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_age_gauge.cpp b/libs/meter/meter_types/test/test_age_gauge.cpp new file mode 100644 index 0000000..56198b1 --- /dev/null +++ b/libs/meter/meter_types/test/test_age_gauge.cpp @@ -0,0 +1,30 @@ +#include +#include + +#include + +class AgeGaugeTest : public ::testing::Test +{ + protected: + MeterId tid = MeterId("age_gauge"); +}; + +TEST_F(AgeGaugeTest, Now) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + AgeGauge g(tid); + EXPECT_TRUE(writer->IsEmpty()); + g.Now(); + EXPECT_EQ("A:age_gauge:0", writer->LastLine()); +} + +TEST_F(AgeGaugeTest, Set) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + AgeGauge g(tid); + EXPECT_TRUE(writer->IsEmpty()); + g.Set(10); + EXPECT_EQ("A:age_gauge:10", writer->LastLine()); +} \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_counter.cpp b/libs/meter/meter_types/test/test_counter.cpp new file mode 100644 index 0000000..c31948c --- /dev/null +++ b/libs/meter/meter_types/test/test_counter.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include + +class CounterTest : public ::testing::Test +{ + protected: + MeterId tid = MeterId("counter"); +}; + +TEST_F(CounterTest, increment) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + + Counter c(tid); + EXPECT_TRUE(writer->IsEmpty()); + c.Increment(); + EXPECT_EQ("c:counter:1.000000", writer->LastLine()); + c.Increment(2); + EXPECT_EQ("c:counter:2.000000", writer->LastLine()); +} + +TEST_F(CounterTest, incrementNegative) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + + Counter c(tid); + c.Increment(-1); + EXPECT_TRUE(writer->IsEmpty()); +} \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_dist_summary.cpp b/libs/meter/meter_types/test/test_dist_summary.cpp new file mode 100644 index 0000000..21cccae --- /dev/null +++ b/libs/meter/meter_types/test/test_dist_summary.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include + +class DistSummaryTest : public ::testing::Test +{ + protected: + MeterId tid = MeterId("dist_summary"); +}; + +TEST_F(DistSummaryTest, record) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + DistributionSummary ds(tid); + EXPECT_TRUE(writer->IsEmpty()); + + ds.Record(42); + EXPECT_EQ("d:dist_summary:42", writer->LastLine()); +} + +TEST_F(DistSummaryTest, recordNegative) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + DistributionSummary ds(tid); + EXPECT_TRUE(writer->IsEmpty()); + + ds.Record(-42); + EXPECT_TRUE(writer->IsEmpty()); +} + +TEST_F(DistSummaryTest, recordZero) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + DistributionSummary ds(tid); + EXPECT_TRUE(writer->IsEmpty()); + + ds.Record(0); + EXPECT_EQ("d:dist_summary:0", writer->LastLine()); +} \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_gauge.cpp b/libs/meter/meter_types/test/test_gauge.cpp new file mode 100644 index 0000000..d0c5d4e --- /dev/null +++ b/libs/meter/meter_types/test/test_gauge.cpp @@ -0,0 +1,30 @@ +#include +#include + +#include + +class GaugeTest : public ::testing::Test +{ + protected: + MeterId tid = MeterId("gauge"); +}; + +TEST_F(GaugeTest, Now) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + Gauge g(tid); + EXPECT_TRUE(writer->IsEmpty()); + g.Set(1); + EXPECT_EQ("g:gauge:1.000000", writer->LastLine()); +} + +TEST_F(GaugeTest, TTL) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + Gauge g(tid, 10); + EXPECT_TRUE(writer->IsEmpty()); + g.Set(42); + EXPECT_EQ("g,10:gauge:42.000000", writer->LastLine()); +} \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_max_gauge.cpp b/libs/meter/meter_types/test/test_max_gauge.cpp new file mode 100644 index 0000000..1598d64 --- /dev/null +++ b/libs/meter/meter_types/test/test_max_gauge.cpp @@ -0,0 +1,20 @@ +#include +#include + +#include + +class MaxGaugeTest : public ::testing::Test +{ + protected: + MeterId tid = MeterId("max_gauge"); +}; + +TEST_F(MaxGaugeTest, Set) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + MaxGauge g(tid); + EXPECT_TRUE(writer->IsEmpty()); + g.Set(0); + EXPECT_EQ("m:max_gauge:0.000000", writer->LastLine()); +} \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_monotonic_counter.cpp b/libs/meter/meter_types/test/test_monotonic_counter.cpp new file mode 100644 index 0000000..7e19de6 --- /dev/null +++ b/libs/meter/meter_types/test/test_monotonic_counter.cpp @@ -0,0 +1,30 @@ +#include +#include + +#include + +class MonotonicCounterTest : public ::testing::Test +{ + protected: + MeterId tid = MeterId("monotonic_counter"); +}; + +TEST_F(MonotonicCounterTest, SetValue) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + MonotonicCounter mc(tid); + EXPECT_TRUE(writer->IsEmpty()); + mc.Set(1); + EXPECT_EQ("C:monotonic_counter:1.000000", writer->LastLine()); +} + +TEST_F(MonotonicCounterTest, SetNegativeValue) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + MonotonicCounter mc(tid); + EXPECT_TRUE(writer->IsEmpty()); + mc.Set(-1); + EXPECT_EQ("C:monotonic_counter:-1.000000", writer->LastLine()); +} \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp new file mode 100644 index 0000000..61580f4 --- /dev/null +++ b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp @@ -0,0 +1,32 @@ +#include +#include + +#include + +class MonoCounterTest : public ::testing::Test +{ + protected: + MeterId tid = MeterId("monotonic_counter_uint"); +}; + +TEST_F(MonoCounterTest, set) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + MonotonicCounterUint mc(tid); + EXPECT_TRUE(writer->IsEmpty()); + + mc.Set(1); + EXPECT_EQ("U:monotonic_counter_uint:1", writer->LastLine()); +} + +TEST_F(MonoCounterTest, setNegative) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + MonotonicCounterUint mc(tid); + EXPECT_TRUE(writer->IsEmpty()); + + mc.Set(-1); + EXPECT_EQ("U:monotonic_counter_uint:18446744073709551615", writer->LastLine()); +} \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp new file mode 100644 index 0000000..9235c2f --- /dev/null +++ b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include + +class PercentileDistSummaryTest : public ::testing::Test +{ + protected: + MeterId tid = MeterId("percentile_dist_summary"); +}; + +TEST_F(PercentileDistSummaryTest, record) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + PercentileDistributionSummary pds(tid); + EXPECT_TRUE(writer->IsEmpty()); + + pds.Record(42); + EXPECT_EQ("D:percentile_dist_summary:42", writer->LastLine()); +} + +TEST_F(PercentileDistSummaryTest, recordNegative) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + PercentileDistributionSummary pds(tid); + EXPECT_TRUE(writer->IsEmpty()); + + pds.Record(-42); + EXPECT_TRUE(writer->IsEmpty()); +} + +TEST_F(PercentileDistSummaryTest, recordZero) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + PercentileDistributionSummary pds(tid); + EXPECT_TRUE(writer->IsEmpty()); + + pds.Record(0); + EXPECT_EQ("D:percentile_dist_summary:0", writer->LastLine()); +} \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_percentile_timer.cpp b/libs/meter/meter_types/test/test_percentile_timer.cpp new file mode 100644 index 0000000..5616ce0 --- /dev/null +++ b/libs/meter/meter_types/test/test_percentile_timer.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include + +class PercentileTimerTest : public ::testing::Test +{ + protected: + MeterId tid = MeterId("percentile_timer"); +}; + +TEST_F(PercentileTimerTest, record) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + PercentileTimer pt(tid); + EXPECT_TRUE(writer->IsEmpty()); + + pt.Record(42); + EXPECT_EQ("T:percentile_timer:42.000000", writer->LastLine()); +} + +TEST_F(PercentileTimerTest, recordNegative) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + PercentileTimer pt(tid); + EXPECT_TRUE(writer->IsEmpty()); + + pt.Record(-42); + EXPECT_TRUE(writer->IsEmpty()); +} + +TEST_F(PercentileTimerTest, recordZero) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + PercentileTimer pt(tid); + EXPECT_TRUE(writer->IsEmpty()); + + pt.Record(0); + EXPECT_EQ("T:percentile_timer:0.000000", writer->LastLine()); +} \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_timer.cpp b/libs/meter/meter_types/test/test_timer.cpp new file mode 100644 index 0000000..df885d2 --- /dev/null +++ b/libs/meter/meter_types/test/test_timer.cpp @@ -0,0 +1,43 @@ +#include +#include + +#include + +class TimerTest : public ::testing::Test +{ + protected: + MeterId tid = MeterId("timer"); +}; + +TEST_F(TimerTest, record) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + Timer t(tid); + EXPECT_TRUE(writer->IsEmpty()); + + t.Record(42); + EXPECT_EQ("t:timer:42.000000", writer->LastLine()); +} + +TEST_F(TimerTest, recordNegative) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + Timer t(tid); + EXPECT_TRUE(writer->IsEmpty()); + + t.Record(-42); + EXPECT_TRUE(writer->IsEmpty()); +} + +TEST_F(TimerTest, recordZero) +{ + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + Timer t(tid); + EXPECT_TRUE(writer->IsEmpty()); + + t.Record(0); + EXPECT_EQ("t:timer:0.000000", writer->LastLine()); +} \ No newline at end of file diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt new file mode 100644 index 0000000..1d7e6af --- /dev/null +++ b/libs/utils/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(spectator-utils STATIC + src/util.cpp + include/singleton.h + include/util.h +) + +target_include_directories(spectator-utils + PUBLIC + ${CMAKE_SOURCE_DIR} +) + +target_link_libraries(spectator-utils + PUBLIC + spectator-meter-id +) \ No newline at end of file diff --git a/libs/utils/include/singleton.h b/libs/utils/include/singleton.h new file mode 100644 index 0000000..5be62b3 --- /dev/null +++ b/libs/utils/include/singleton.h @@ -0,0 +1,22 @@ +#pragma once +// Templated Singleton for derived singleton classes + +template class Singleton +{ + protected: + // Protected constructor & destructor allow derived classes to instantiate + Singleton() = default; + virtual ~Singleton() = default; + + public: + // Prevent copying + Singleton(const Singleton &) = delete; + Singleton &operator=(const Singleton &) = delete; + + // Get the singleton instance + static T &GetInstance() + { + static T instance; + return instance; + } +}; diff --git a/libs/utils/include/util.h b/libs/utils/include/util.h new file mode 100644 index 0000000..238b70e --- /dev/null +++ b/libs/utils/include/util.h @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include + +#include +struct ProtocolLine +{ + char symbol; + MeterId id; + std::string value; + + bool operator==(const ProtocolLine &other) const + { + return symbol == other.symbol && id == other.id && value == other.value; + } + + std::string to_string() const + { + std::stringstream ss; + ss << symbol << ":" << id.GetName(); + + // Sort tags by key + std::map sorted_tags(id.GetTags().begin(), id.GetTags().end()); + + // Add tags if there are any + if (!sorted_tags.empty()) + { + ss << ","; + bool first = true; + for (const auto &[key, value] : sorted_tags) + { + if (!first) + { + ss << ","; + } + ss << key << "=" << value; + first = false; + } + } + + // Add the value + ss << ":" << value; + + return ss.str(); + } +}; + +std::optional ParseProtocolLine(const std::string &line); \ No newline at end of file diff --git a/libs/utils/src/util.cpp b/libs/utils/src/util.cpp new file mode 100644 index 0000000..7d3723c --- /dev/null +++ b/libs/utils/src/util.cpp @@ -0,0 +1,57 @@ +#include + +#include +#include + +// Utility: split a string by a delimiter +std::vector split(const std::string &str, char delimiter) +{ + std::vector tokens; + std::stringstream ss(str); + std::string item; + while (std::getline(ss, item, delimiter)) + { + tokens.push_back(item); + } + return tokens; +} + +std::optional ParseProtocolLine(const std::string &line) +{ + char symbol{}; + std::string name{}; + std::unordered_map tags{}; + std::string value{}; + + auto mainParts = split(line, ':'); + + if (mainParts.size() < 3) + { + return std::nullopt; + } + + auto symbolParts = split(mainParts[0], ','); + if (!symbolParts.empty() && !symbolParts[0].empty()) + { + symbol = symbolParts[0][0]; + } + + auto idParts = split(mainParts[1], ','); + if (!idParts.empty()) + { + name = idParts[0]; + + for (size_t i = 1; i < idParts.size(); ++i) + { + auto tagParts = split(idParts[i], '='); + if (tagParts.size() == 2) + { + tags[tagParts[0]] = tagParts[1]; + } + } + } + + // The last part is the value + value = mainParts[2]; + return ProtocolLine{symbol, MeterId{name, tags}, value}; +} \ No newline at end of file diff --git a/libs/writer/CMakeLists.txt b/libs/writer/CMakeLists.txt new file mode 100644 index 0000000..b874a0b --- /dev/null +++ b/libs/writer/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(writer_wrapper) +add_subdirectory(writer_types) +add_subdirectory(writer_config) \ No newline at end of file diff --git a/libs/writer/writer_config/CMakeLists.txt b/libs/writer/writer_config/CMakeLists.txt new file mode 100644 index 0000000..58d1d53 --- /dev/null +++ b/libs/writer/writer_config/CMakeLists.txt @@ -0,0 +1,29 @@ +add_library(spectator-writer-config STATIC + src/writer_config.cpp + include/writer_config.h +) + +target_include_directories(spectator-writer-config + PUBLIC + ${CMAKE_SOURCE_DIR} +) + + +target_link_libraries(spectator-writer-config + PUBLIC + spectator-writer-types +) + +add_executable(test_writer_config + test/test_writer_config.cpp) + +target_link_libraries(test_writer_config + PRIVATE + spectator-writer-config + spectator-writer-types + GTest::gtest + GTest::gmock + GTest::gtest_main +) + +add_test(NAME writer_config_test COMMAND test_writer_config) diff --git a/libs/writer/writer_config/include/writer_config.h b/libs/writer/writer_config/include/writer_config.h new file mode 100644 index 0000000..01059d7 --- /dev/null +++ b/libs/writer/writer_config/include/writer_config.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include +#include + +class WriterConfig +{ + public: + WriterConfig(std::string type); + + const WriterType &GetType() const noexcept { return m_type; }; + + const std::string &GetLocation() const noexcept { return m_location;}; + + private: + WriterType m_type; + std::string m_location; +}; \ No newline at end of file diff --git a/libs/writer/writer_config/src/writer_config.cpp b/libs/writer/writer_config/src/writer_config.cpp new file mode 100644 index 0000000..6c288a4 --- /dev/null +++ b/libs/writer/writer_config/src/writer_config.cpp @@ -0,0 +1,52 @@ +#include + +std::pair GetWriterConfigFromString(const std::string &type) +{ + // Check exact matches first + auto it = TypeToLocationMap.find(type); + if (it != TypeToLocationMap.end()) + { + return {it->second.first, std::string(it->second.second)}; + } + + else if (type.rfind(WriterTypes::UDPURL, 0) == 0) + { + return {WriterType::UDP, type}; + } + else if (type.rfind(WriterTypes::UnixURL, 0) == 0) + { + return {WriterType::Unix, type}; + } + + throw std::invalid_argument("Invalid writer type: " + type); +} + + + +WriterConfig::WriterConfig(std::string type) +{ + const char *envLocation = std::getenv("SPECTATOR_OUTPUT_LOCATION"); + + try + { + if (envLocation != nullptr) + { + // If environment variable is set, use it instead of the constructor parameter + std::string envValue(envLocation); + auto [writer_type, location] = GetWriterConfigFromString(envValue); + m_type = writer_type; + m_location = location; + } + else + { + // If no environment variable, use the type passed to the constructor + auto [writer_type, location] = GetWriterConfigFromString(type); + m_type = writer_type; + m_location = location; + } + } + catch (const std::invalid_argument &e) + { + throw std::invalid_argument("Invalid writer type: " + (envLocation != nullptr ? std::string(envLocation) : type)); + } +} \ No newline at end of file diff --git a/libs/writer/writer_config/test/test_writer_config.cpp b/libs/writer/writer_config/test/test_writer_config.cpp new file mode 100644 index 0000000..2056290 --- /dev/null +++ b/libs/writer/writer_config/test/test_writer_config.cpp @@ -0,0 +1,169 @@ +#include + +#include +#include + +#include + +// Helper to temporarily set an environment variable for testing +class EnvironmentVariableSetter +{ + public: + EnvironmentVariableSetter(const std::string &name, const std::string &value) : m_name(name) + { + // Store original value (might be nullptr) + m_originalValue = std::getenv(name.c_str()); + + // Set the new value + setenv(name.c_str(), value.c_str(), 1); + } + + ~EnvironmentVariableSetter() + { + // Restore original state + if (m_originalValue) + setenv(m_name.c_str(), m_originalValue, 1); + else + unsetenv(m_name.c_str()); + } + + private: + std::string m_name; + const char *m_originalValue; +}; + +// Helper to temporarily unset an environment variable for testing +class EnvironmentVariableUnset +{ + public: + EnvironmentVariableUnset(const std::string &name) : m_name(name) + { + // Store original value (might be nullptr) + m_originalValue = std::getenv(name.c_str()); + + // Always unset regardless of whether it was set before + unsetenv(name.c_str()); + } + + ~EnvironmentVariableUnset() + { + // Only restore if there was an original value + if (m_originalValue) + setenv(m_name.c_str(), m_originalValue, 1); + } + + private: + std::string m_name; + const char *m_originalValue; +}; + +// Test fixture for WriterConfig tests +class WriterConfigTest : public ::testing::Test +{ + protected: + void SetUp() override + { + // Ensure environment variable is unset before each test + unsetenv("SPECTATOR_OUTPUT_LOCATION"); + } +}; + +// Test basic writer type initialization +TEST_F(WriterConfigTest, BasicWriterTypes) +{ + + + // Test "memory" type + { + WriterConfig config(WriterTypes::Memory); + EXPECT_EQ(config.GetType(), WriterType::Memory); + EXPECT_EQ(config.GetLocation(), DefaultLocations::NoLocation); + } + + // Test "udp" type + { + WriterConfig config(WriterTypes::UDP); + EXPECT_EQ(config.GetType(), WriterType::UDP); + EXPECT_EQ(config.GetLocation(), DefaultLocations::UDP); + } + + // Test "unix" type + { + WriterConfig config(WriterTypes::Unix); + EXPECT_EQ(config.GetType(), WriterType::Unix); + EXPECT_EQ(config.GetLocation(), DefaultLocations::UDS); + } +} + +// Test URL-based writer initialization +TEST_F(WriterConfigTest, URLBasedWriterTypes) +{ + + // Test UDP URL + { + const std::string udpUrl = std::string(WriterTypes::UDPURL) + "192.168.1.100:8125"; + WriterConfig config(udpUrl); + EXPECT_EQ(config.GetType(), WriterType::UDP); + EXPECT_EQ(config.GetLocation(), udpUrl); + } + + // Test Unix domain socket URL + { + const std::string unixUrl = std::string(WriterTypes::UnixURL) + "/var/run/custom/socket.sock"; + WriterConfig config(unixUrl); + EXPECT_EQ(config.GetType(), WriterType::Unix); + EXPECT_EQ(config.GetLocation(), unixUrl); + } +} + +// Test environment variable override +TEST_F(WriterConfigTest, EnvironmentVariableOverride) +{ + // Test environment variable overriding constructor parameter + { + EnvironmentVariableSetter setter("SPECTATOR_OUTPUT_LOCATION", WriterTypes::Memory); + WriterConfig config(WriterTypes::UDP); // This should be ignored due to env var + EXPECT_EQ(config.GetType(), WriterType::Memory); + EXPECT_EQ(config.GetLocation(), DefaultLocations::NoLocation); + } + + + // Test with environment variable unset + { + EnvironmentVariableUnset unset("SPECTATOR_OUTPUT_LOCATION"); + WriterConfig config(WriterTypes::Memory); + EXPECT_EQ(config.GetType(), WriterType::Memory); + EXPECT_EQ(config.GetLocation(), DefaultLocations::NoLocation); + } +} + +// Test invalid writer type handling +TEST_F(WriterConfigTest, InvalidWriterType) +{ + // Test invalid type from constructor + EXPECT_THROW({ WriterConfig config("invalid_type"); }, std::invalid_argument); + + // Test invalid type from environment variable + { + EnvironmentVariableSetter setter("SPECTATOR_OUTPUT_LOCATION", "invalid_env_value"); + EXPECT_THROW( + { + WriterConfig config("none"); // This should be ignored, env var used instead + }, + std::invalid_argument); + } +} + +// Test case for edge cases +TEST_F(WriterConfigTest, EdgeCases) +{ + // Test empty string + EXPECT_THROW({ WriterConfig config(""); }, std::invalid_argument); + + // Test with just URL scheme but no path + { + WriterConfig config("udp://"); + EXPECT_EQ(config.GetType(), WriterType::UDP); + EXPECT_EQ(config.GetLocation(), "udp://"); + } +} \ No newline at end of file diff --git a/libs/writer/writer_types/CMakeLists.txt b/libs/writer/writer_types/CMakeLists.txt new file mode 100644 index 0000000..989d21b --- /dev/null +++ b/libs/writer/writer_types/CMakeLists.txt @@ -0,0 +1,55 @@ +add_subdirectory(test_utils) + +add_library(spectator-writer-types + src/memory_writer.cpp + src/udp_writer.cpp + src/uds_writer.cpp +) + +target_include_directories(spectator-writer-types + PUBLIC + ${CMAKE_SOURCE_DIR} +) + +target_link_libraries(spectator-writer-types + PUBLIC + spectator-logger + Boost::system +) + +set(TEST_SOURCES + test/test_memory_writer.cpp + test/test_udp_writer.cpp + test/test_uds_writer.cpp +) + + +# Create individual test executables for each test file +foreach(test_file ${TEST_SOURCES}) + # Get the filename without extension and path + get_filename_component(test_name ${test_file} NAME_WE) + + # Create an executable for this test file + add_executable(${test_name} ${test_file}) + + # Include test directory and server directories + target_include_directories(${test_name} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/test + ${CMAKE_CURRENT_SOURCE_DIR}/test_utils/udp_server + ${CMAKE_CURRENT_SOURCE_DIR}/test_utils/uds_server + ) + + # Link against GTest and other required libraries + target_link_libraries(${test_name} PRIVATE + GTest::GTest + GTest::Main + spectator-writer-types + udp_server_lib + uds_server_lib + ) + + # Add the test to CTest + add_test(NAME ${test_name} COMMAND ${test_name}) +endforeach() + diff --git a/libs/writer/writer_types/include/base/base_writer.h b/libs/writer/writer_types/include/base/base_writer.h new file mode 100644 index 0000000..3b7ca8b --- /dev/null +++ b/libs/writer/writer_types/include/base/base_writer.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +class BaseWriter +{ + public: + BaseWriter() = default; + virtual ~BaseWriter() = default; + + BaseWriter(const BaseWriter &) = delete; + BaseWriter &operator=(const BaseWriter &) = delete; + BaseWriter(BaseWriter &&) = delete; + BaseWriter &operator=(BaseWriter &&) = delete; + + virtual void Write(const std::string &message) = 0; + virtual void Close() = 0; +}; \ No newline at end of file diff --git a/libs/writer/writer_types/include/memory_writer.h b/libs/writer/writer_types/include/memory_writer.h new file mode 100644 index 0000000..757b064 --- /dev/null +++ b/libs/writer/writer_types/include/memory_writer.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +class MemoryWriter final : public BaseWriter +{ + public: + MemoryWriter() = default; + ~MemoryWriter() override = default; + + void Write(const std::string &message) override; + void Close() override; + void Clear(); + + const std::vector &GetMessages() const noexcept + { + return m_messages; + } + + const std::string &LastLine() const noexcept; + + bool IsEmpty() const noexcept { return m_messages.empty(); } + + private: + std::vector m_messages; +}; diff --git a/libs/writer/writer_types/include/udp_writer.h b/libs/writer/writer_types/include/udp_writer.h new file mode 100644 index 0000000..4f10cdb --- /dev/null +++ b/libs/writer/writer_types/include/udp_writer.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include +#include + +class UDPWriter final : public BaseWriter +{ + public: + UDPWriter(const std::string &host, int port); + ~UDPWriter() override; + void Write(const std::string &message) override; + void Close() override; + + private: + std::string m_host; + int m_port; + std::unique_ptr m_io_context; + std::unique_ptr m_socket; + boost::asio::ip::udp::endpoint m_endpoint; +}; diff --git a/libs/writer/writer_types/include/uds_writer.h b/libs/writer/writer_types/include/uds_writer.h new file mode 100644 index 0000000..9ac404b --- /dev/null +++ b/libs/writer/writer_types/include/uds_writer.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include +#include +#include + +class UDSWriter final : public BaseWriter +{ + public: + UDSWriter(const std::string &socketPath); + ~UDSWriter() override; + void Write(const std::string &message) override; + void Close() override; + + private: + std::string m_socketPath; + std::unique_ptr m_ioContext; + std::unique_ptr m_socket; + bool m_isOpen; + + // Helper method to initialize the connection + bool connect(); +}; diff --git a/libs/writer/writer_types/include/writer_types.h b/libs/writer/writer_types/include/writer_types.h new file mode 100644 index 0000000..0409d0e --- /dev/null +++ b/libs/writer/writer_types/include/writer_types.h @@ -0,0 +1,43 @@ +#pragma once + +#include "memory_writer.h" +#include "udp_writer.h" +#include "uds_writer.h" + +#include +#include +#include +#include +#include + +// Enum to specify which writer type to create +enum class WriterType +{ + Memory, + UDP, + Unix +}; + +struct WriterTypes +{ + static constexpr auto Memory = "memory"; + static constexpr auto UDP = "udp"; + static constexpr auto Unix = "unix"; + + // URL prefixes + static constexpr auto UDPURL = "udp://"; + static constexpr auto UnixURL = "unix://"; +}; + +struct DefaultLocations +{ + static constexpr auto NoLocation = ""; + static constexpr auto UDP = "udp://127.0.0.1:1234"; + static constexpr auto UDS = "unix:///run/spectatord/spectatord.unix"; +}; + +inline const std::map> TypeToLocationMap = { + {WriterTypes::Memory, {WriterType::Memory, DefaultLocations::NoLocation}}, + {WriterTypes::UDP, {WriterType::UDP, DefaultLocations::UDP}}, + {WriterTypes::Unix, {WriterType::Unix, DefaultLocations::UDS}}, +}; \ No newline at end of file diff --git a/libs/writer/writer_types/src/memory_writer.cpp b/libs/writer/writer_types/src/memory_writer.cpp new file mode 100644 index 0000000..e6b6efe --- /dev/null +++ b/libs/writer/writer_types/src/memory_writer.cpp @@ -0,0 +1,33 @@ +#include + +#include + +void MemoryWriter::Write(const std::string &message) +{ + this->m_messages.push_back(message); + Logger::debug("MemoryWriter::Writing: {}", message); +} + +void MemoryWriter::Close() +{ + this->Clear(); + Logger::debug("MemoryWriter::Closed"); +} + +void MemoryWriter::Clear() +{ + this->m_messages.clear(); + Logger::debug("MemoryWriter::Cleared messages"); +} + +const std::string &MemoryWriter::LastLine() const noexcept +{ + static const std::string emptyString = ""; + + if (true == m_messages.empty()) + { + return emptyString; + } + + return this->m_messages.back(); +} diff --git a/libs/writer/writer_types/src/udp_writer.cpp b/libs/writer/writer_types/src/udp_writer.cpp new file mode 100644 index 0000000..7a15a6d --- /dev/null +++ b/libs/writer/writer_types/src/udp_writer.cpp @@ -0,0 +1,81 @@ +#include + +#include + +#include + +UDPWriter::UDPWriter(const std::string &host, int port) : m_host(host), m_port(port) +{ + try + { + // Create io_context + m_io_context = std::make_unique(); + + // Create socket + m_socket = std::make_unique(*m_io_context); + m_socket->open(boost::asio::ip::udp::v4()); + + // Resolve the endpoint + boost::asio::ip::udp::resolver resolver(*m_io_context); + m_endpoint = *resolver.resolve(boost::asio::ip::udp::v4(), m_host, std::to_string(m_port)).begin(); + } + catch (const boost::system::system_error &e) + { + Logger::error("UDPWriter: Failed to initialize connection: {}", e.what()); + Close(); + } +} + +UDPWriter::~UDPWriter() +{ + Close(); +} + +void UDPWriter::Write(const std::string &message) +try +{ + if (m_socket == nullptr || m_socket->is_open() == false) + { + Logger::error("UDPWriter: Socket not initialized or closed"); + return; + } + + boost::system::error_code ec; + size_t sent = m_socket->send_to(boost::asio::buffer(message.data(), message.size()), m_endpoint, 0, ec); + + if (ec) + { + Logger::error("UDPWriter: Failed to send message: {}", ec.message()); + } + else if (sent != message.size()) + { + Logger::warn("UDPWriter: Sent only {} bytes out of {} bytes", sent, message.size()); + } +} +catch (const std::exception &e) +{ + Logger::error("UDPWriter: Exception during write: {}", e.what()); +} + +void UDPWriter::Close() +try +{ + + if (m_socket && m_socket->is_open()) + { + boost::system::error_code ec; + m_socket->close(ec); + if (ec) + { + Logger::warn("UDPWriter: Error when closing socket: {}", ec.message()); + } + } + + // Reset the unique_ptr to deallocate resources + m_socket.reset(); + m_io_context.reset(); +} +catch (const std::exception &e) +{ + Logger::error("UDPWriter: Exception during close: {}", e.what()); +} \ No newline at end of file diff --git a/libs/writer/writer_types/src/uds_writer.cpp b/libs/writer/writer_types/src/uds_writer.cpp new file mode 100644 index 0000000..4acafa4 --- /dev/null +++ b/libs/writer/writer_types/src/uds_writer.cpp @@ -0,0 +1,116 @@ +#include + +#include + + +#include +#include +#include + +namespace local = boost::asio::local; + +UDSWriter::UDSWriter(const std::string &socketPath) + : m_socketPath(socketPath), m_ioContext(std::make_unique()), m_socket(nullptr), + m_isOpen(false) +{ + connect(); +} + +UDSWriter::~UDSWriter() +{ + Close(); +} + +bool UDSWriter::connect() +{ + if (m_isOpen) + { + return true; // Already connected + } + + try + { + // Create a new socket if needed + if (!m_socket) + { + m_socket = std::make_unique(*m_ioContext); + } + + // Connect to the UDS server + local::stream_protocol::endpoint endpoint(m_socketPath); + + boost::system::error_code ec; + m_socket->connect(endpoint, ec); + + if (ec) + { + Logger::error("UDS Writer: Failed to connect to {} - {}", m_socketPath, ec.message()); + return false; + } + + m_isOpen = true; + Logger::debug("UDS Writer: Connected to {}", m_socketPath); + return true; + } + catch (const std::exception &e) + { + Logger::error("UDS Writer: Exception while connecting - {}", e.what()); + m_isOpen = false; + return false; + } +} + +void UDSWriter::Write(const std::string &message) +{ + if (!m_isOpen && !connect()) + { + Logger::error("UDS Writer: Cannot write - not connected to {}", m_socketPath); + return; + } + + try + { + boost::system::error_code ec; + boost::asio::write(*m_socket, boost::asio::buffer(message), ec); + + if (ec) + { + Logger::error("UDS Writer: Failed to send message - {}", ec.message()); + m_isOpen = false; // Mark as disconnected on error + } + else + { + Logger::debug("UDS Writer: Sent message ({} bytes)", message.size()); + } + } + catch (const std::exception &e) + { + Logger::error("UDS Writer: Exception while sending message - {}", e.what()); + m_isOpen = false; // Mark as disconnected on exception + } +} + +void UDSWriter::Close() +{ + if (m_socket && m_isOpen) + { + try + { + boost::system::error_code ec; + m_socket->shutdown(local::stream_protocol::socket::shutdown_both, ec); + m_socket->close(ec); + + if (ec) + { + Logger::warn("UDS Writer: Error closing socket - {}", ec.message()); + } + } + catch (const std::exception &e) + { + Logger::warn("UDS Writer: Exception while closing socket - {}", e.what()); + } + } + + m_isOpen = false; + Logger::debug("UDS Writer: Connection closed"); +} diff --git a/libs/writer/writer_types/test/test_memory_writer.cpp b/libs/writer/writer_types/test/test_memory_writer.cpp new file mode 100644 index 0000000..fb61302 --- /dev/null +++ b/libs/writer/writer_types/test/test_memory_writer.cpp @@ -0,0 +1,50 @@ +#include +#include + +TEST(MemoryWriterTest, IsEmpty) +{ + auto writer = MemoryWriter(); + EXPECT_TRUE(writer.IsEmpty()); +} + +TEST(MemoryWriterTest, Write) +{ + auto writer = MemoryWriter(); + writer.Write("Test message"); + EXPECT_FALSE(writer.IsEmpty()); + EXPECT_EQ(writer.LastLine(), "Test message"); +} + +TEST(MemoryWriterTest, Clear) +{ + auto writer = MemoryWriter(); + writer.Write("Test message"); + EXPECT_FALSE(writer.IsEmpty()); + + writer.Clear(); + EXPECT_TRUE(writer.IsEmpty()); +} + +TEST(MemoryWriterTest, GetMessages) +{ + auto writer = MemoryWriter(); + writer.Write("First message"); + writer.Write("Second message"); + + const auto &messages = writer.GetMessages(); + EXPECT_EQ(messages.size(), 2); + EXPECT_EQ(messages[0], "First message"); + EXPECT_EQ(messages[1], "Second message"); +} + +TEST(MemoryWriterTest, LastLine) +{ + auto writer = MemoryWriter(); + writer.Write("First message"); + writer.Write("Second message"); + + EXPECT_EQ(writer.LastLine(), "Second message"); + + writer.Clear(); + EXPECT_EQ(writer.LastLine(), ""); +} \ No newline at end of file diff --git a/libs/writer/writer_types/test/test_udp_writer.cpp b/libs/writer/writer_types/test/test_udp_writer.cpp new file mode 100644 index 0000000..152d8cb --- /dev/null +++ b/libs/writer/writer_types/test/test_udp_writer.cpp @@ -0,0 +1,137 @@ +#include + +#include + +#include "../test_utils/udp_server/udp_server.h" // Include our new header for UDP server interaction +#include +#include +#include // For std::find + +// Test fixture for UDP Writer tests +class UDPWriterTest : public ::testing::Test +{ + protected: + void SetUp() override + { + // Set the server to run + server_running = true; + + // Clear any existing messages from previous tests + clear_messages(); + + // Start the UDP server in a separate thread + server_thread = std::thread( + []() + { + // This calls our server function directly + listen_for_udp_messages(); + }); + + // Give the server time to start + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + + void TearDown() override + { + // Signal the server to stop + server_running = false; + + // Terminate the server thread + if (server_thread.joinable()) + { + server_thread.join(); + } + } + + std::thread server_thread; +}; + +TEST_F(UDPWriterTest, SendMessage) +{ + // Create a UDP writer that will connect to localhost:1234 + UDPWriter writer("127.0.0.1", 1234); + + // Define our test message + std::string test_message = "Hello from UDP Writer Test"; + + // Send a test message + writer.Write(test_message); + + // Give time for the message to be processed + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Get current messages and verify the message was received + auto messages = get_messages(); + ASSERT_FALSE(messages.empty()); + + // Check that our message is in the vector + bool message_found = false; + for (const auto &msg : messages) + { + if (msg == test_message) + { + message_found = true; + break; + } + } +} + +TEST_F(UDPWriterTest, CloseAndReopen) +{ + + UDPWriter writer("127.0.0.1", 1234); + std::string message1 = "Initial message"; + writer.Write(message1); + + // Wait for message processing + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Verify first message + auto messages = get_messages(); + ASSERT_FALSE(messages.empty()); + ASSERT_EQ(messages.back(), message1); + + // Close the writer + writer.Close(); + + // Create a new writer + UDPWriter writer2("127.0.0.1", 1234); + std::string message2 = "Message after reopening"; + writer2.Write(message2); + + // Wait for message processing + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Verify second message + messages = get_messages(); + ASSERT_GE(messages.size(), 2); + ASSERT_EQ(messages.back(), message2); +} + +TEST_F(UDPWriterTest, SendMultipleMessages) +{ + + UDPWriter writer("127.0.0.1", 1234); + + // Define test messages + std::vector test_messages = {"Message 1", "Message 2", "Message 3"}; + + // Send several messages in succession + for (const auto &msg : test_messages) + { + writer.Write(msg); + } + + // Give time for messages to be processed + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Get received messages and verify + auto received_messages = get_messages(); + + // Verify we received at least the number of messages we sent + ASSERT_EQ(received_messages.size(), test_messages.size()); + + ASSERT_EQ(test_messages.at(0), received_messages.at(0)); + ASSERT_EQ(test_messages.at(1), received_messages.at(1)); + ASSERT_EQ(test_messages.at(2), received_messages.at(2)); +} \ No newline at end of file diff --git a/libs/writer/writer_types/test/test_uds_writer.cpp b/libs/writer/writer_types/test/test_uds_writer.cpp new file mode 100644 index 0000000..9bc40e9 --- /dev/null +++ b/libs/writer/writer_types/test/test_uds_writer.cpp @@ -0,0 +1,139 @@ + +#include + +#include +#include "../test_utils/uds_server/uds_server.h" +#include +#include +#include + +// Test fixture for UDS Writer tests +class UDSWriterTest : public ::testing::Test +{ + protected: + void SetUp() override + { + // Set the server to run + uds_server_running = true; + + // Clear any existing messages from previous tests + clear_uds_messages(); + + // Start the UDS server in a separate thread + server_thread = std::thread( + []() + { + // This calls our server function directly + listen_for_uds_messages(); + }); + + // Give the server time to start + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + + void TearDown() override + { + // Signal the server to stop + uds_server_running = false; + + // Terminate the server thread + if (server_thread.joinable()) + { + server_thread.join(); + } + } + + std::thread server_thread; +}; + +TEST_F(UDSWriterTest, SendMessage) +{ + // Create a UDS writer that will connect to the test socket + UDSWriter writer("/tmp/test_uds_socket"); + + // Define our test message + std::string test_message = "Hello from UDS Writer Test"; + + // Send a test message + writer.Write(test_message); + + // Give time for the message to be processed + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Get current messages and verify the message was received + auto messages = get_uds_messages(); + ASSERT_FALSE(messages.empty()); + + // Check that our message is in the vector + bool message_found = false; + for (const auto &msg : messages) + { + if (msg == test_message) + { + message_found = true; + break; + } + } + + ASSERT_TRUE(message_found); +} + +TEST_F(UDSWriterTest, CloseAndReopen) +{ + UDSWriter writer("/tmp/test_uds_socket"); + std::string message1 = "Initial message"; + writer.Write(message1); + + // Wait for message processing + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Verify first message + auto messages = get_uds_messages(); + ASSERT_FALSE(messages.empty()); + ASSERT_EQ(messages.back(), message1); + + // Close the writer + writer.Close(); + + // Create a new writer + UDSWriter writer2("/tmp/test_uds_socket"); + std::string message2 = "Message after reopening"; + writer2.Write(message2); + + // Wait for message processing + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + // Verify second message + messages = get_uds_messages(); + ASSERT_GE(messages.size(), 2); + ASSERT_EQ(messages.back(), message2); +} + +TEST_F(UDSWriterTest, SendMultipleMessages) +{ + UDSWriter writer("/tmp/test_uds_socket"); + + // Define test messages + std::vector test_messages = {"Message 1", "Message 2", "Message 3"}; + + // Send messages one by one, with a separate connection for each + for (const auto &msg : test_messages) + { + writer.Write(msg); + // Wait for the message to be processed + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + std::this_thread::sleep_for(std::chrono::milliseconds(300)); + + // Get received messages and verify + auto received_messages = get_uds_messages(); + + // Verify we received the number of messages we sent + ASSERT_EQ(received_messages.size(), test_messages.size()); + + // Verify each message was received correctly + for (size_t i = 0; i < test_messages.size(); i++) + { + ASSERT_EQ(test_messages.at(i), received_messages.at(i)); + } +} \ No newline at end of file diff --git a/libs/writer/writer_types/test_utils/CMakeLists.txt b/libs/writer/writer_types/test_utils/CMakeLists.txt new file mode 100644 index 0000000..1c5c70d --- /dev/null +++ b/libs/writer/writer_types/test_utils/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(udp_server) +add_subdirectory(uds_server) \ No newline at end of file diff --git a/libs/writer/writer_types/test_utils/udp_server/CMakeLists.txt b/libs/writer/writer_types/test_utils/udp_server/CMakeLists.txt new file mode 100644 index 0000000..9f8c88c --- /dev/null +++ b/libs/writer/writer_types/test_utils/udp_server/CMakeLists.txt @@ -0,0 +1,31 @@ + # Create a shared UDP server library for tests +add_library(udp_server_lib OBJECT + udp_server.cpp +) +target_include_directories(udp_server_lib + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) +target_compile_definitions(udp_server_lib + PUBLIC + UDP_SERVER_LIB_ONLY +) +target_link_libraries(udp_server_lib + PUBLIC + Boost::system + pthread +) + +# UDP Server executable +add_executable(udp_server + udp_server.cpp +) +target_include_directories(udp_server + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../../../include + ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(udp_server + PUBLIC + Boost::system +) \ No newline at end of file diff --git a/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp b/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp new file mode 100644 index 0000000..ec4bcf2 --- /dev/null +++ b/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp @@ -0,0 +1,126 @@ +#include "udp_server.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//---------- Message Storage Implementation ---------- + +// Vector to store all received messages +std::vector messages = {}; +std::mutex messages_mutex; + +// Flag to control server shutdown +std::atomic server_running(true); + +// Expose functions to interact with the messages vector +std::vector get_messages() +{ + std::lock_guard lock(messages_mutex); + return messages; +} + +void clear_messages() +{ + std::lock_guard lock(messages_mutex); + messages.clear(); +} + +void add_message(const std::string &message) +{ + std::lock_guard lock(messages_mutex); + messages.push_back(message); +} + +//---------- UDP Server Implementation ---------- + +void listen_for_udp_messages() +try +{ + const unsigned short port = 1234; + + boost::asio::io_context io_context; + + // Create an IPv4 socket bound to localhost (127.0.0.1) and port 1234 + boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string("127.0.0.1"), port); + boost::asio::ip::udp::socket socket(io_context, boost::asio::ip::udp::v4()); + + try + { + socket.bind(endpoint); + std::cout << "Socket bound to IPv4 localhost (127.0.0.1):" << port << std::endl; + } + catch (const std::exception &e) + { + std::cerr << "Error binding socket: " << e.what() << "\n"; + throw; + } + + std::array buffer; + boost::asio::ip::udp::endpoint sender_endpoint; + + std::cout << "UDP server listening on 127.0.0.1:" << port << " (IPv4 localhost)\n"; + + // Configure socket with a small timeout so we can check the run flag + socket.non_blocking(true); + + while (server_running) + { + try + { + std::size_t bytes_received = socket.receive_from(boost::asio::buffer(buffer), sender_endpoint); + + if (bytes_received == buffer.size()) + { + std::cout << "Warning: Received datagram might have been truncated (buffer full)" << std::endl; + } + + // Create string from received data and store it in the messages vector + std::string message(buffer.data(), bytes_received); + + // Add the message to our global message storage + add_message(message); + + // Get the current count of messages + auto current_messages = get_messages(); + + std::cout << "Received from " << sender_endpoint << ": " << message << std::endl; + std::cout << "Total messages stored: " << current_messages.size() << std::endl; + } + catch (const boost::system::system_error &e) + { + if (e.code() == boost::asio::error::would_block) + { + // No data available, just wait a bit and try again + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + else + { + std::cerr << "Error receiving data: " << e.what() << std::endl; + break; + } + } + } + std::cout << "UDP server shutting down..." << std::endl; +} +catch (const std::exception &e) +{ + std::cerr << "Exception in UDP server: " << e.what() << "\n"; + return; +} + +//---------- Main Function ---------- + +// Only compile the main function when building the executable, not the library +#ifndef UDP_SERVER_LIB_ONLY +int main() +{ + listen_for_udp_messages(); + return 0; +} +#endif diff --git a/libs/writer/writer_types/test_utils/udp_server/udp_server.h b/libs/writer/writer_types/test_utils/udp_server/udp_server.h new file mode 100644 index 0000000..2514ec9 --- /dev/null +++ b/libs/writer/writer_types/test_utils/udp_server/udp_server.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include + +// Functions to interact with the UDP server's message storage +std::vector get_messages(); +void clear_messages(); +void add_message(const std::string &message); + +// Function to run the server in a thread - can be used by both the server executable and tests +void listen_for_udp_messages(); + +// Flag to control server shutdown - used to gracefully stop the server +extern std::atomic server_running; diff --git a/libs/writer/writer_types/test_utils/uds_server/CMakeLists.txt b/libs/writer/writer_types/test_utils/uds_server/CMakeLists.txt new file mode 100644 index 0000000..2a0a618 --- /dev/null +++ b/libs/writer/writer_types/test_utils/uds_server/CMakeLists.txt @@ -0,0 +1,31 @@ +# Create a shared UDS server library for tests +add_library(uds_server_lib OBJECT + uds_server.cpp +) +target_include_directories(uds_server_lib + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) +target_compile_definitions(uds_server_lib + PUBLIC + UDS_SERVER_LIB_ONLY +) +target_link_libraries(uds_server_lib + PUBLIC + Boost::system + pthread +) + +# UDS Server executable +add_executable(uds_server + uds_server.cpp +) +target_include_directories(uds_server + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/../../../include + ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(uds_server + PUBLIC + Boost::system +) diff --git a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp new file mode 100644 index 0000000..173887a --- /dev/null +++ b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp @@ -0,0 +1,153 @@ +#include "uds_server.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//---------- Message Storage Implementation ---------- + +// Vector to store all received messages +std::vector uds_messages = {}; +std::mutex uds_messages_mutex; + +// Flag to control server shutdown +std::atomic uds_server_running(true); + +// Expose functions to interact with the messages vector +std::vector get_uds_messages() +{ + std::lock_guard lock(uds_messages_mutex); + return uds_messages; +} + +void clear_uds_messages() +{ + std::lock_guard lock(uds_messages_mutex); + uds_messages.clear(); +} + +void add_uds_message(const std::string &message) +{ + std::lock_guard lock(uds_messages_mutex); + uds_messages.push_back(message); +} + +//---------- UDS Server Implementation ---------- + +void listen_for_uds_messages() +try +{ + // Path to the Unix domain socket + const std::string socket_path = "/tmp/test_uds_socket"; + + // Remove any existing socket file + std::filesystem::remove(socket_path); + + boost::asio::io_context io_context; + + // Create and open a Unix domain socket + boost::asio::local::stream_protocol::endpoint endpoint(socket_path); + boost::asio::local::stream_protocol::acceptor acceptor(io_context, endpoint); + + std::cout << "UDS server listening on " << socket_path << std::endl; + + while (uds_server_running) + { + // Create a socket for the client connection + boost::asio::local::stream_protocol::socket socket(io_context); + + try + { + // Set acceptor to non-blocking so we can check the run flag + acceptor.non_blocking(true); + + boost::system::error_code ec; + acceptor.accept(socket, ec); + + if (ec) + { + if (ec == boost::asio::error::would_block) + { + // No connection available, wait a bit and try again + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + continue; + } + else + { + std::cerr << "Error accepting connection: " << ec.message() << std::endl; + continue; + } + } + + // Connection accepted, set back to blocking for data reading + socket.non_blocking(false); + + // Buffer for reading data + std::array buffer; + while (true) + { + boost::system::error_code read_ec; + std::size_t bytes_read = socket.read_some(boost::asio::buffer(buffer), read_ec); + + if (read_ec == boost::asio::error::eof) + { + // Connection closed cleanly by peer + break; + } + else if (read_ec) + { + std::cerr << "Error reading from socket: " << read_ec.message() << std::endl; + break; + } + + if (bytes_read == buffer.size()) + { + std::cout << "Warning: Received data might have been truncated (buffer full)" << std::endl; + } + + // Create string from received data and store it + std::string message(buffer.data(), bytes_read); + add_uds_message(message); + auto current_messages = get_uds_messages(); + std::cout << "Received message: " << message << std::endl; + std::cout << "Total messages stored: " << current_messages.size() << std::endl; + } + // Close the connection + socket.close(); + } + catch (const std::exception &e) + { + std::cerr << "Exception handling client: " << e.what() << std::endl; + } + } + + std::cout << "UDS server shutting down..." << std::endl; + + // Clean up the socket file on exit + std::filesystem::remove(socket_path); +} +catch (const std::exception &e) +{ + std::cerr << "Exception in UDS server: " << e.what() << std::endl; + return; +} + +//---------- Main Function ---------- + +// Only compile the main function when building the executable, not the library +#ifndef UDS_SERVER_LIB_ONLY +int main() +{ + listen_for_uds_messages(); + return 0; +} +#endif \ No newline at end of file diff --git a/libs/writer/writer_types/test_utils/uds_server/uds_server.h b/libs/writer/writer_types/test_utils/uds_server/uds_server.h new file mode 100644 index 0000000..b03873f --- /dev/null +++ b/libs/writer/writer_types/test_utils/uds_server/uds_server.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include + +// Functions to interact with the UDS server's message storage +std::vector get_uds_messages(); +void clear_uds_messages(); +void add_uds_message(const std::string &message); + +// Function to run the server in a thread - can be used by both the server executable and tests +void listen_for_uds_messages(); + +// Flag to control server shutdown - used to gracefully stop the server +extern std::atomic uds_server_running; \ No newline at end of file diff --git a/libs/writer/writer_wrapper/CMakeLists.txt b/libs/writer/writer_wrapper/CMakeLists.txt new file mode 100644 index 0000000..5267439 --- /dev/null +++ b/libs/writer/writer_wrapper/CMakeLists.txt @@ -0,0 +1,9 @@ +add_library(spectator-writer-wrapper + src/Writer.cpp +) + +target_link_libraries(spectator-writer-wrapper + PUBLIC + spectator-logger + spectator-writer-types +) \ No newline at end of file diff --git a/libs/writer/writer_wrapper/include/Writer.h b/libs/writer/writer_wrapper/include/Writer.h new file mode 100644 index 0000000..1ffd5f9 --- /dev/null +++ b/libs/writer/writer_wrapper/include/Writer.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +#include +#include + + +class Writer final : public Singleton +{ + public: + virtual ~Writer(); + + + private: + friend class Singleton; + friend class Registry; + friend class WriterTestHelper; + friend class AgeGauge; + friend class Counter; + friend class DistributionSummary; + friend class Gauge; + friend class MaxGauge; + friend class MonotonicCounter; + friend class MonotonicCounterUint; + friend class PercentileDistributionSummary; + friend class PercentileTimer; + friend class Timer; + + // Private constructor - enforces singleton pattern + Writer() = default; + + static void Initialize(WriterType type, const std::string ¶m = "", int port = 0); + + static void Write(const std::string &message); + + static void Close(); + + static WriterType GetWriterType(); + + // Get the Writer's implementation for testing purposes + static BaseWriter *GetImpl() + { + return Writer::GetInstance().m_impl.get(); + } + /** + * Reset the writer to uninitialized state + * This method is private and can only be called by Registry + */ + static void Reset(); + + // Implementation details + std::unique_ptr m_impl; + WriterType m_currentType = WriterType::Memory; // Default type +}; \ No newline at end of file diff --git a/libs/writer/writer_wrapper/include/writer_test_helper.h b/libs/writer/writer_wrapper/include/writer_test_helper.h new file mode 100644 index 0000000..81e82cc --- /dev/null +++ b/libs/writer/writer_wrapper/include/writer_test_helper.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +/** + * WriterTestHelper - A utility class to help with testing Writer functionality + * + * This class is a friend of Writer and can provide access to Writer's private + * methods for testing purposes. + */ +class WriterTestHelper +{ + public: + // Initialize the Writer for testing purposes + static void InitializeWriter(WriterType type, const std::string ¶m = "", int port = 0) + { + Writer::Initialize(type, param, port); + } + + // Reset the Writer for testing purposes + static void ResetWriter() + { + Writer::Reset(); + } + + // Get the Writer's implementation for testing purposes + static BaseWriter *GetImpl() + { + return Writer::GetInstance().m_impl.get(); + } +}; diff --git a/libs/writer/writer_wrapper/src/Writer.cpp b/libs/writer/writer_wrapper/src/Writer.cpp new file mode 100644 index 0000000..e1ba3de --- /dev/null +++ b/libs/writer/writer_wrapper/src/Writer.cpp @@ -0,0 +1,111 @@ +#include + +#include +#include +#include + +Writer::~Writer() +{ + // No need to explicitly close here as unique_ptr will clean up +} + +void Writer::Initialize(WriterType type, const std::string ¶m, int port) +{ + // Get the singleton instance directly + auto &instance = GetInstance(); + + // Create the new writer based on type + try + { + switch (type) + { + case WriterType::Memory: + instance.m_impl = std::make_unique(); + Logger::info("Writer initialized as MemoryWriter"); + break; + case WriterType::UDP: + instance.m_impl = std::make_unique(param, port); + Logger::info("Writer initialized as UDPWriter with host: {} and port: {}", param, port); + break; + case WriterType::Unix: + instance.m_impl = std::make_unique(param); + Logger::info("Writer initialized as UnixWriter with socket path: {}", param); + break; + default: + throw std::runtime_error("Unsupported writer type"); + } + + instance.m_currentType = type; + } + catch (const std::exception &e) + { + Logger::error("Failed to initialize writer: {}", e.what()); + throw; + } +} + +void Writer::Reset() +{ + auto &instance = GetInstance(); + + if (instance.m_impl) + { + try + { + instance.m_impl->Close(); + } + catch (const std::exception &e) + { + Logger::warn("Exception while closing writer during reset: {}", e.what()); + } + } + + instance.m_impl.reset(); + Logger::info("Writer has been reset"); +} + +void Writer::Write(const std::string &message) +{ + auto &instance = GetInstance(); + + if (!instance.m_impl) + { + Logger::error("Attempted to write with uninitialized writer implementation"); + return; + } + + try + { + instance.m_impl->Write(message); + } + catch (const std::exception &e) + { + Logger::error("Write operation failed: {}", e.what()); + } +} + +void Writer::Close() +{ + auto &instance = GetInstance(); + + if (!instance.m_impl) + { + Logger::debug("Close called on uninitialized writer"); + return; + } + + try + { + instance.m_impl->Close(); + Logger::debug("Writer closed successfully"); + } + catch (const std::exception &e) + { + Logger::error("Failed to close writer: {}", e.what()); + } +} + +WriterType Writer::GetWriterType() +{ + return GetInstance().m_currentType; +} diff --git a/requirements.txt b/requirements.txt index 548109e..b047f71 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -conan==2.16.1 +conan==2.16.1 \ No newline at end of file diff --git a/sanitized b/sanitized deleted file mode 100644 index 316ba9a..0000000 --- a/sanitized +++ /dev/null @@ -1,9 +0,0 @@ -include(default) - -# https://blog.conan.io/2022/04/21/New-conan-release-1-47.html -# -# inject sanitizer flags into conan packages, so that we do not get segfaults when -# we try to run the local build with the address sanitizer for debug builds - -[conf] -tools.build:cxxflags=["-fno-omit-frame-pointer", "-fsanitize=address"] diff --git a/setup-venv.sh b/setup-venv.sh old mode 100755 new mode 100644 index 7bfcded..94532d8 --- a/setup-venv.sh +++ b/setup-venv.sh @@ -18,4 +18,4 @@ if [[ -f requirements.txt ]]; then # use the virtualenv python python -m pip install --upgrade pip wheel python -m pip install --requirement requirements.txt -fi +fi \ No newline at end of file diff --git a/spectator/CMakeLists.txt b/spectator/CMakeLists.txt new file mode 100644 index 0000000..40e14d2 --- /dev/null +++ b/spectator/CMakeLists.txt @@ -0,0 +1,24 @@ +add_library(registry + src/registry.cpp +) +target_include_directories(registry + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include +) +target_link_libraries(registry + PUBLIC + spectator-config + spectator-meter-id + spectator-meter-types + spectator-writer-config + spectator-writer-wrapper + +) +add_executable(registry-test test/test_registry.cpp) +target_link_libraries(registry-test PRIVATE + GTest::gtest + GTest::gtest_main + registry + spectator-utils +) +add_test(NAME registry-test COMMAND registry-test) \ No newline at end of file diff --git a/spectator/age_gauge_test.cc b/spectator/age_gauge_test.cc deleted file mode 100644 index 844e1f9..0000000 --- a/spectator/age_gauge_test.cc +++ /dev/null @@ -1,36 +0,0 @@ -#include "stateless_meters.h" -#include "test_publisher.h" -#include - -namespace { - -using spectator::Id; -using spectator::AgeGauge; -using spectator::Tags; -using spectator::TestPublisher; - -TEST(AgeGauge, Set) { - TestPublisher publisher; - auto id = std::make_shared("gauge", Tags{}); - auto id2 = std::make_shared("gauge2", Tags{{"key", "val"}}); - AgeGauge g{id, &publisher}; - AgeGauge g2{id2, &publisher}; - - g.Set(1671641328); - g2.Set(1671641028.3); - g.Set(0); - std::vector expected = {"A:gauge:1671641328", - "A:gauge2,key=val:1671641028.3", - "A:gauge:0"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - -TEST(AgeGauge, InvalidTags) { - TestPublisher publisher; - // test with a single tag, because tags order is not guaranteed in a flat_hash_map - auto id = std::make_shared("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo", - Tags{{"tag1,:=", "value1,:="}}); - AgeGauge g{id, &publisher}; - EXPECT_EQ("A:test______^____-_~______________.___foo,tag1___=value1___:", g.GetPrefix()); -} -} // namespace diff --git a/spectator/config.h b/spectator/config.h deleted file mode 100644 index f959dbb..0000000 --- a/spectator/config.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include -#include - -namespace spectator { - -struct Config { - std::string endpoint; - std::unordered_map common_tags; - uint32_t bytes_to_buffer; -}; - -} // namespace spectator diff --git a/spectator/counter_test.cc b/spectator/counter_test.cc deleted file mode 100644 index 91267ce..0000000 --- a/spectator/counter_test.cc +++ /dev/null @@ -1,42 +0,0 @@ -#include "stateless_meters.h" -#include "test_publisher.h" -#include - -namespace { - -using spectator::Counter; -using spectator::Id; -using spectator::Tags; -using spectator::TestPublisher; - -TEST(Counter, Activity) { - TestPublisher publisher; - auto id = std::make_shared("ctr.name", Tags{}); - auto id2 = std::make_shared("c2", Tags{{"key", "val"}}); - Counter c{id, &publisher}; - Counter c2{id2, &publisher}; - c.Increment(); - c2.Add(1.2); - c.Add(0.1); - std::vector expected = {"c:ctr.name:1", "c:c2,key=val:1.2", - "c:ctr.name:0.1"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - -TEST(Counter, Id) { - TestPublisher publisher; - Counter c{std::make_shared("foo", Tags{{"key", "val"}}), - &publisher}; - auto id = std::make_shared("foo", Tags{{"key", "val"}}); - EXPECT_EQ(*(c.MeterId()), *id); -} - -TEST(Counter, InvalidTags) { - TestPublisher publisher; - // test with a single tag, because tags order is not guaranteed in a flat_hash_map - auto id = std::make_shared("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo", - Tags{{"tag1,:=", "value1,:="}}); - Counter c{id, &publisher}; - EXPECT_EQ("c:test______^____-_~______________.___foo,tag1___=value1___:", c.GetPrefix()); -} -} // namespace diff --git a/spectator/dist_summary_test.cc b/spectator/dist_summary_test.cc deleted file mode 100644 index ed8eec5..0000000 --- a/spectator/dist_summary_test.cc +++ /dev/null @@ -1,33 +0,0 @@ -#include "stateless_meters.h" -#include "test_publisher.h" -#include - -namespace { -using spectator::DistributionSummary; -using spectator::Id; -using spectator::Tags; -using spectator::TestPublisher; - -TEST(DistributionSummary, Record) { - TestPublisher publisher; - auto id = std::make_shared("ds.name", Tags{}); - auto id2 = std::make_shared("ds2", Tags{{"key", "val"}}); - DistributionSummary d{id, &publisher}; - DistributionSummary d2{id2, &publisher}; - d.Record(10); - d2.Record(1.2); - d.Record(0.1); - std::vector expected = {"d:ds.name:10", "d:ds2,key=val:1.2", - "d:ds.name:0.1"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - -TEST(DistributionSummary, InvalidTags) { - TestPublisher publisher; - // test with a single tag, because tags order is not guaranteed in a flat_hash_map - auto id = std::make_shared("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo", - Tags{{"tag1,:=", "value1,:="}}); - DistributionSummary d{id, &publisher}; - EXPECT_EQ("d:test______^____-_~______________.___foo,tag1___=value1___:", d.GetPrefix()); -} -} // namespace diff --git a/spectator/gauge_test.cc b/spectator/gauge_test.cc deleted file mode 100644 index 75c5fbf..0000000 --- a/spectator/gauge_test.cc +++ /dev/null @@ -1,51 +0,0 @@ -#include "stateless_meters.h" -#include "test_publisher.h" -#include - -namespace { - -using spectator::Gauge; -using spectator::Id; -using spectator::Tags; -using spectator::TestPublisher; - -TEST(Gauge, Set) { - TestPublisher publisher; - auto id = std::make_shared("gauge", Tags{}); - auto id2 = std::make_shared("gauge2", Tags{{"key", "val"}}); - Gauge g{id, &publisher}; - Gauge g2{id2, &publisher}; - - g.Set(42); - g2.Set(2); - g.Set(1); - std::vector expected = {"g:gauge:42", "g:gauge2,key=val:2", - "g:gauge:1"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - -TEST(Gauge, SetWithTTL) { - TestPublisher publisher; - auto id = std::make_shared("gauge", Tags{}); - auto id2 = std::make_shared("gauge2", Tags{{"key", "val"}}); - Gauge g{id, &publisher, 1}; - Gauge g2{id2, &publisher, 2}; - - g.Set(42); - g2.Set(2); - g.Set(1); - std::vector expected = {"g,1:gauge:42", "g,2:gauge2,key=val:2", - "g,1:gauge:1"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - - -TEST(Gauge, InvalidTags) { - TestPublisher publisher; - // test with a single tag, because tags order is not guaranteed in a flat_hash_map - auto id = std::make_shared("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo", - Tags{{"tag1,:=", "value1,:="}}); - Gauge g{id, &publisher}; - EXPECT_EQ("g:test______^____-_~______________.___foo,tag1___=value1___:", g.GetPrefix()); -} -} // namespace diff --git a/spectator/id.h b/spectator/id.h deleted file mode 100644 index e766874..0000000 --- a/spectator/id.h +++ /dev/null @@ -1,223 +0,0 @@ -#pragma once - -#include "absl/container/flat_hash_map.h" -#include "absl/strings/string_view.h" -#include -#include -#include -#include -#include - -namespace spectator { - -class Tags { - using table_t = absl::flat_hash_map; - table_t entries_; - - public: - Tags() = default; - - Tags(std::initializer_list> vs) { - for (auto& pair : vs) { - add(pair.first, pair.second); - } - } - - template - static Tags from(Cont&& cont) { - Tags tags; - tags.entries_.reserve(cont.size()); - for (auto&& kv : cont) { - tags.add(kv.first, kv.second); - } - return tags; - } - - void add(absl::string_view k, absl::string_view v) { - entries_[k] = std::string(v); - } - - [[nodiscard]] size_t hash() const { - using hs = std::hash; - size_t h = 0; - for (const auto& entry : entries_) { - h += (hs()(entry.first) << 1U) ^ hs()(entry.second); - } - return h; - } - - void move_all(Tags&& source) { - entries_.insert(std::make_move_iterator(source.begin()), - std::make_move_iterator(source.end())); - } - - bool operator==(const Tags& that) const { return that.entries_ == entries_; } - - [[nodiscard]] bool has(absl::string_view key) const { - return entries_.find(key) != entries_.end(); - } - - [[nodiscard]] std::string at(absl::string_view key) const { - auto entry = entries_.find(key); - if (entry != entries_.end()) { - return entry->second; - } - return {}; - } - - [[nodiscard]] size_t size() const { return entries_.size(); } - - [[nodiscard]] table_t::const_iterator begin() const { - return entries_.begin(); - } - - [[nodiscard]] table_t::const_iterator end() const { return entries_.end(); } -}; - -class Id { - public: - Id(absl::string_view name, Tags tags) noexcept - : name_(name), tags_(std::move(tags)), hash_(0u) {} - - static std::shared_ptr of(absl::string_view name, Tags tags = {}) { - return std::make_shared(name, std::move(tags)); - } - - bool operator==(const Id& rhs) const noexcept { - return name_ == rhs.name_ && tags_ == rhs.tags_; - } - - const std::string& Name() const noexcept { return name_; } - - const Tags& GetTags() const noexcept { return tags_; } - - std::unique_ptr WithTag(const std::string& key, - const std::string& value) const { - // Create a copy - Tags tags{GetTags()}; - tags.add(key, value); - return std::make_unique(Name(), tags); - } - - std::unique_ptr WithTags(Tags&& extra_tags) const { - Tags tags{GetTags()}; - tags.move_all(std::move(extra_tags)); - return std::make_unique(Name(), tags); - } - - std::unique_ptr WithTags(const Tags& extra_tags) const { - Tags tags{GetTags()}; - for (const auto& t : extra_tags) { - tags.add(t.first, t.second); - } - return std::make_unique(Name(), tags); - } - - std::unique_ptr WithStat(const std::string& stat) const { - return WithTag("statistic", stat); - }; - - static std::shared_ptr WithDefaultStat(std::shared_ptr baseId, - const std::string& stat) { - if (baseId->GetTags().has("statistic")) { - return baseId; - } else { - return baseId->WithStat(stat); - } - } - - friend struct std::hash; - - friend struct std::hash>; - - private: - std::string name_; - Tags tags_; - mutable size_t hash_; - - size_t Hash() const noexcept { - if (hash_ == 0) { - // compute hash code, and reuse it - hash_ = tags_.hash() ^ std::hash()(name_); - } - return hash_; - } -}; - -using IdPtr = std::shared_ptr; - -} // namespace spectator - -namespace std { -template <> -struct hash { - size_t operator()(const spectator::Id& id) const { return id.Hash(); } -}; - -template <> -struct hash { - size_t operator()(const spectator::Tags& tags) const { return tags.hash(); } -}; - -template <> -struct hash> { - size_t operator()(const shared_ptr& id) const { - return id->Hash(); - } -}; - -template <> -struct equal_to> { - bool operator()(const shared_ptr& lhs, - const shared_ptr& rhs) const { - return *lhs == *rhs; - } -}; - -} // namespace std - -template <> struct fmt::formatter: fmt::formatter { - auto format(const spectator::Tags& tags, format_context& ctx) const -> format_context::iterator { - std::string s; - auto size = tags.size(); - - if (size > 0) { - // sort keys, to ensure stable output - std::vector keys; - for (const auto& pair : tags) { - keys.push_back(pair.first); - } - std::sort(keys.begin(), keys.end()); - - s = "["; - for (const auto &key : keys) { - if (size > 1) { - s += key + "=" + tags.at(key) + ", "; - } else { - s += key + "=" + tags.at(key) + "]"; - } - size -= 1; - } - } else { - s = "[]"; - } - - return fmt::formatter::format(s, ctx); - } -}; - -inline auto operator<<(std::ostream& os, const spectator::Tags& tags) -> std::ostream& { - os << fmt::format("{}", tags); - return os; -} - -template <> struct fmt::formatter: fmt::formatter { - static auto format(const spectator::Id& id, format_context& ctx) -> format_context::iterator { - return fmt::format_to(ctx.out(), "Id(name={}, tags={})", id.Name(), id.GetTags()); - } -}; - -inline auto operator<<(std::ostream& os, const spectator::Id& id) -> std::ostream& { - os << fmt::format("{}", id); - return os; -} diff --git a/spectator/id_test.cc b/spectator/id_test.cc deleted file mode 100644 index 6ac8baf..0000000 --- a/spectator/id_test.cc +++ /dev/null @@ -1,42 +0,0 @@ -#include "../spectator/id.h" -#include - -namespace { - -using spectator::Id; -using spectator::Tags; - -TEST(Id, Create) { - Id id{"foo", Tags{}}; - EXPECT_EQ(id.Name(), "foo"); - EXPECT_EQ(id.GetTags().size(), 0); - EXPECT_EQ(fmt::format("{}", id), "Id(name=foo, tags=[])"); - - Id id_tags_single{"name", Tags{{"k", "v"}}}; - EXPECT_EQ(id_tags_single.Name(), "name"); - EXPECT_EQ(id_tags_single.GetTags().size(), 1); - EXPECT_EQ(fmt::format("{}", id_tags_single), "Id(name=name, tags=[k=v])"); - - Id id_tags_multiple{"name", Tags{{"k", "v"}, {"k1", "v1"}}}; - EXPECT_EQ(id_tags_multiple.Name(), "name"); - EXPECT_EQ(id_tags_multiple.GetTags().size(), 2); - - EXPECT_EQ(fmt::format("{}", id_tags_multiple), "Id(name=name, tags=[k=v, k1=v1])"); - - std::shared_ptr id_of{Id::of("name", Tags{{"k", "v"}, {"k1", "v1"}})}; - EXPECT_EQ(id_of->Name(), "name"); - EXPECT_EQ(id_of->GetTags().size(), 2); - EXPECT_EQ(fmt::format("{}", *id_of), "Id(name=name, tags=[k=v, k1=v1])"); -} - -TEST(Id, Tags) { - Id id{"foo", Tags{}}; - auto withTag = id.WithTag("k", "v"); - Tags tags{{"k", "v"}}; - EXPECT_EQ(tags, withTag->GetTags()); - - auto withStat = withTag->WithStat("count"); - Tags tagsWithStat{{"k", "v"}, {"statistic", "count"}}; - EXPECT_EQ(tagsWithStat, withStat->GetTags()); -} -} // namespace diff --git a/spectator/include/registry.h b/spectator/include/registry.h new file mode 100644 index 0000000..162fab9 --- /dev/null +++ b/spectator/include/registry.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include +#include // Include Writer.h + +#include +#include +#include +#include +#include +#include + +class Registry +{ + public: + explicit Registry(const Config &config); + ~Registry(); + + MeterId new_id(const std::string &name, const std::unordered_map &tags = {}) const; + + AgeGauge age_gauge(const std::string &name, + const std::unordered_map &tags = std::unordered_map()); + + AgeGauge age_gauge_with_id(const MeterId &meter_id); + + Counter counter(const std::string &name, + const std::unordered_map &tags = std::unordered_map()); + + Counter counter_with_id(const MeterId &meter_id); + + DistributionSummary distribution_summary( + const std::string &name, const std::unordered_map &tags = std::unordered_map()); + + DistributionSummary distribution_summary_with_id(const MeterId &meter_id); + + Gauge gauge(const std::string &name, + const std::unordered_map &tags = std::unordered_map(), + const std::optional &ttl_seconds = std::nullopt); + + Gauge gauge_with_id(const MeterId &meter_id, const std::optional &ttl_seconds = std::nullopt); + + MaxGauge max_gauge(const std::string &name, + const std::unordered_map &tags = std::unordered_map()); + + MaxGauge max_gauge_with_id(const MeterId &meter_id); + + MonotonicCounter monotonic_counter( + const std::string &name, const std::unordered_map &tags = std::unordered_map()); + + MonotonicCounter monotonic_counter_with_id(const MeterId &meter_id); + + MonotonicCounterUint monotonic_counter_uint( + const std::string &name, const std::unordered_map &tags = std::unordered_map()); + + MonotonicCounterUint monotonic_counter_uint_with_id(const MeterId &meter_id); + + PercentileDistributionSummary pct_distribution_summary( + const std::string &name, const std::unordered_map &tags = std::unordered_map()); + + PercentileDistributionSummary pct_distribution_summary_with_id(const MeterId &meter_id); + + PercentileTimer pct_timer(const std::string &name, + const std::unordered_map &tags = std::unordered_map()); + + PercentileTimer pct_timer_with_id(const MeterId &meter_id); + + Timer timer(const std::string &name, + const std::unordered_map &tags = std::unordered_map()); + + Timer timer_with_id(const MeterId &meter_id); + + private: + Config m_config; +}; \ No newline at end of file diff --git a/spectator/log_entry.h b/spectator/log_entry.h deleted file mode 100644 index 27cebc4..0000000 --- a/spectator/log_entry.h +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -#include "registry.h" -#include "strings.h" -#include "percentile_timer.h" - -namespace spectator { -class LogEntry { - public: - LogEntry(Registry* registry, std::string method, const std::string& url) - : registry_{registry}, - start_{absl::Now()}, - id_{registry_->CreateId("ipc.client.call", - Tags{{"owner", "spectator-cpp"}, - {"ipc.endpoint", PathFromUrl(url)}, - {"http.method", std::move(method)}, - {"http.status", "-1"}})} {} - - absl::Time start() const { return start_; } - - void log() { - using millis = std::chrono::milliseconds; - using std::chrono::seconds; - registry_->GetPercentileTimer(id_, millis(1), seconds(5)) - ->Record(absl::Now() - start_); - } - - void set_status_code(int code) { - id_ = id_->WithTag("http.status", fmt::format("{}", code)); - } - - void set_attempt(int attempt_number, bool is_final) { - id_ = id_->WithTag("ipc.attempt", attempt(attempt_number)) - ->WithTag("ipc.attempt.final", is_final ? "true" : "false"); - } - - void set_error(const std::string& error) { - id_ = id_->WithTag("ipc.result", "failure")->WithTag("ipc.status", error); - } - - void set_success() { - const std::string ipc_success = "success"; - id_ = id_->WithTag("ipc.status", ipc_success) - ->WithTag("ipc.result", ipc_success); - } - - private: - Registry* registry_; - absl::Time start_; - IdPtr id_; - - std::string attempt(int attempt_number) { - static std::string initial = "initial"; - static std::string second = "second"; - static std::string third_up = "third_up"; - - switch (attempt_number) { - case 0: - return initial; - case 1: - return second; - default: - return third_up; - } - } -}; - -} // namespace spectator diff --git a/spectator/logger.cc b/spectator/logger.cc deleted file mode 100644 index 361ee8d..0000000 --- a/spectator/logger.cc +++ /dev/null @@ -1,29 +0,0 @@ -#include "logger.h" -#include -#include -#include - -namespace spectator { - -static constexpr const char* const kMainLogger = "spectator"; - -LogManager& log_manager() noexcept { - static auto* the_log_manager = new LogManager(); - return *the_log_manager; -} - -LogManager::LogManager() noexcept { - try { - logger_ = spdlog::create_async_nb( - kMainLogger); - logger_->set_level(spdlog::level::debug); - } catch (const spdlog::spdlog_ex& ex) { - std::cerr << "Log initialization failed: " << ex.what() << "\n"; - } -} - -std::shared_ptr LogManager::Logger() noexcept { - return logger_; -} - -} // namespace spectator diff --git a/spectator/logger.h b/spectator/logger.h deleted file mode 100644 index 1c78eef..0000000 --- a/spectator/logger.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include - -namespace spectator { - -class LogManager { - public: - LogManager() noexcept; - std::shared_ptr Logger() noexcept; - - private: - std::shared_ptr logger_; -}; - -LogManager& log_manager() noexcept; - -inline std::shared_ptr DefaultLogger() noexcept { - return log_manager().Logger(); -} - -} // namespace spectator diff --git a/spectator/max_gauge_test.cc b/spectator/max_gauge_test.cc deleted file mode 100644 index 10c5bac..0000000 --- a/spectator/max_gauge_test.cc +++ /dev/null @@ -1,35 +0,0 @@ -#include "stateless_meters.h" -#include "test_publisher.h" -#include - -namespace { - -using spectator::Id; -using spectator::MaxGauge; -using spectator::Tags; -using spectator::TestPublisher; - -TEST(MaxGauge, Set) { - TestPublisher publisher; - auto id = std::make_shared("gauge", Tags{}); - auto id2 = std::make_shared("gauge2", Tags{{"key", "val"}}); - MaxGauge g{id, &publisher}; - MaxGauge g2{id2, &publisher}; - - g.Set(42); - g2.Update(2); - g.Update(1); - std::vector expected = {"m:gauge:42", "m:gauge2,key=val:2", - "m:gauge:1"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - -TEST(MaxGauge, InvalidTags) { - TestPublisher publisher; - // test with a single tag, because tags order is not guaranteed in a flat_hash_map - auto id = std::make_shared("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo", - Tags{{"tag1,:=", "value1,:="}}); - MaxGauge g{id, &publisher}; - EXPECT_EQ("m:test______^____-_~______________.___foo,tag1___=value1___:", g.GetPrefix()); -} -} // namespace diff --git a/spectator/measurement.h b/spectator/measurement.h deleted file mode 100644 index ad88200..0000000 --- a/spectator/measurement.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "id.h" -#include - -namespace spectator { - -struct Measurement { - IdPtr id; - double value; - - bool operator==(const Measurement& other) const { - return std::abs(value - other.value) < 1e-9 && *id == *(other.id); - } - - Measurement(IdPtr idPtr, double v) : id(std::move(idPtr)), value(v) {} -}; - -} // namespace spectator - -template <> struct fmt::formatter: formatter { - static auto format(const spectator::Measurement& m, format_context& ctx) -> format_context::iterator { - return fmt::format_to(ctx.out(), "Measurement({}, {})", *(m.id), m.value); - } -}; diff --git a/spectator/meter_type.h b/spectator/meter_type.h deleted file mode 100644 index 5b2329c..0000000 --- a/spectator/meter_type.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include - -namespace spectator { -enum class MeterType { - AgeGauge, - Counter, - DistSummary, - Gauge, - MaxGauge, - MonotonicCounter, - MonotonicCounterUint, - PercentileDistSummary, - PercentileTimer, - Timer -}; -} - -template <> struct fmt::formatter: formatter { - auto format(spectator::MeterType meter_type, format_context& ctx) const -> format_context::iterator { - using namespace spectator; - std::string_view s = "unknown"; - - switch (meter_type) { - case MeterType::AgeGauge: - s = "age-gauge"; - break; - case MeterType::Counter: - s = "counter"; - break; - case MeterType::DistSummary: - s = "distribution-summary"; - break; - case MeterType::Gauge: - s = "gauge"; - break; - case MeterType::MaxGauge: - s = "max-gauge"; - break; - case MeterType::MonotonicCounter: - s = "monotonic-counter"; - break; - case MeterType::MonotonicCounterUint: - s = "monotonic-counter-uint"; - break; - case MeterType::PercentileDistSummary: - s = "percentile-distribution-summary"; - break; - case MeterType::PercentileTimer: - s = "percentile-timer"; - break; - case MeterType::Timer: - s = "timer"; - break; - } - - return fmt::formatter::format(s, ctx); - } -}; diff --git a/spectator/meter_type_test.cc b/spectator/meter_type_test.cc deleted file mode 100644 index 0a8e318..0000000 --- a/spectator/meter_type_test.cc +++ /dev/null @@ -1,11 +0,0 @@ -#include "../spectator/meter_type.h" -#include - -namespace { - -using spectator::MeterType; - -TEST(MeterType, Format) { - EXPECT_EQ(fmt::format("{}", MeterType::Counter), "counter"); -} -} // namespace diff --git a/spectator/monotonic_counter_test.cc b/spectator/monotonic_counter_test.cc deleted file mode 100644 index 3cf8e39..0000000 --- a/spectator/monotonic_counter_test.cc +++ /dev/null @@ -1,34 +0,0 @@ -#include "stateless_meters.h" -#include "test_publisher.h" -#include - -namespace { - -using spectator::Id; -using spectator::MonotonicCounter; -using spectator::Tags; -using spectator::TestPublisher; - -TEST(MonotonicCounter, Set) { - TestPublisher publisher; - auto id = std::make_shared("ctr", Tags{}); - auto id2 = std::make_shared("ctr2", Tags{{"key", "val"}}); - MonotonicCounter c{id, &publisher}; - MonotonicCounter c2{id2, &publisher}; - - c.Set(42.1); - c2.Set(2); - c.Set(43); - std::vector expected = {"C:ctr:42.1", "C:ctr2,key=val:2", "C:ctr:43"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - -TEST(MonotonicCounter, InvalidTags) { - TestPublisher publisher; - // test with a single tag, because tags order is not guaranteed in a flat_hash_map - auto id = std::make_shared("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo", - Tags{{"tag1,:=", "value1,:="}}); - MonotonicCounter c{id, &publisher}; - EXPECT_EQ("C:test______^____-_~______________.___foo,tag1___=value1___:", c.GetPrefix()); -} -} // namespace diff --git a/spectator/monotonic_counter_uint_test.cc b/spectator/monotonic_counter_uint_test.cc deleted file mode 100644 index d3f55f2..0000000 --- a/spectator/monotonic_counter_uint_test.cc +++ /dev/null @@ -1,34 +0,0 @@ -#include "stateless_meters.h" -#include "test_publisher.h" -#include - -namespace { - -using spectator::Id; -using spectator::MonotonicCounterUint; -using spectator::Tags; -using spectator::TestPublisher; - -TEST(MonotonicCounterUint, Set) { - TestPublisher publisher; - auto id = std::make_shared("ctr", Tags{}); - auto id2 = std::make_shared("ctr2", Tags{{"key", "val"}}); - MonotonicCounterUint c{id, &publisher}; - MonotonicCounterUint c2{id2, &publisher}; - - c.Set(42); - c2.Set(2); - c.Set(-1); - std::vector expected = {"U:ctr:42", "U:ctr2,key=val:2", "U:ctr:18446744073709551615"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - -TEST(MonotonicCounterUint, InvalidTags) { - TestPublisher publisher; - // test with a single tag, because tags order is not guaranteed in a flat_hash_map - auto id = std::make_shared("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo", - Tags{{"tag1,:=", "value1,:="}}); - MonotonicCounterUint c{id, &publisher}; - EXPECT_EQ("U:test______^____-_~______________.___foo,tag1___=value1___:", c.GetPrefix()); -} -} // namespace \ No newline at end of file diff --git a/spectator/perc_dist_summary_test.cc b/spectator/perc_dist_summary_test.cc deleted file mode 100644 index 86b730e..0000000 --- a/spectator/perc_dist_summary_test.cc +++ /dev/null @@ -1,31 +0,0 @@ -#include "stateless_meters.h" -#include "test_publisher.h" -#include - -namespace { -using spectator::Id; -using spectator::PercentileDistributionSummary; -using spectator::Tags; -using spectator::TestPublisher; - -TEST(PercDistSum, Record) { - TestPublisher publisher; - auto id = std::make_shared("pds", Tags{}); - PercentileDistributionSummary d{id, &publisher, 0, 1000}; - d.Record(50); - d.Record(5000); - d.Record(-5000); - std::vector expected = {"D:pds:50", "D:pds:1000", - "D:pds:0"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - -TEST(PercDistSum, InvalidTags) { - TestPublisher publisher; - // test with a single tag, because tags order is not guaranteed in a flat_hash_map - auto id = std::make_shared("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo", - Tags{{"tag1,:=", "value1,:="}}); - PercentileDistributionSummary d{id, &publisher, 0, 1000}; - EXPECT_EQ("D:test______^____-_~______________.___foo,tag1___=value1___:", d.GetPrefix()); -} -} // namespace diff --git a/spectator/perc_timer_test.cc b/spectator/perc_timer_test.cc deleted file mode 100644 index 6301349..0000000 --- a/spectator/perc_timer_test.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include "stateless_meters.h" -#include "test_publisher.h" -#include - -namespace { -using spectator::Id; -using spectator::PercentileTimer; -using spectator::Tags; -using spectator::TestPublisher; - -TEST(PercentileTimer, Record) { - TestPublisher publisher; - auto id = std::make_shared("pt", Tags{}); - PercentileTimer c{id, &publisher, absl::ZeroDuration(), absl::Seconds(5)}; - c.Record(absl::Milliseconds(42)); - c.Record(std::chrono::microseconds(500)); - c.Record(absl::Seconds(10)); - std::vector expected = {"T:pt:0.042", "T:pt:0.0005", "T:pt:5"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - -TEST(PercentileTimer, InvalidTags) { - TestPublisher publisher; - // test with a single tag, because tags order is not guaranteed in a flat_hash_map - auto id = std::make_shared("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo", - Tags{{"tag1,:=", "value1,:="}}); - PercentileTimer t{id, &publisher, absl::ZeroDuration(), absl::Seconds(5)}; - EXPECT_EQ("T:test______^____-_~______________.___foo,tag1___=value1___:", t.GetPrefix()); -} -} // namespace diff --git a/spectator/publisher.cc b/spectator/publisher.cc deleted file mode 100644 index 9658d58..0000000 --- a/spectator/publisher.cc +++ /dev/null @@ -1,166 +0,0 @@ -#include "publisher.h" -#include "logger.h" -#include - -namespace spectator { - -static const char NEW_LINE = '\n'; - -SpectatordPublisher::SpectatordPublisher(absl::string_view endpoint, - uint32_t bytes_to_buffer, - std::shared_ptr logger) - : logger_(std::move(logger)), - udp_socket_(io_context_), - local_socket_(io_context_), bytes_to_buffer_(bytes_to_buffer) { - buffer_.reserve(bytes_to_buffer_ + 1024); - if (absl::StartsWith(endpoint, "unix:")) { - this->unixDomainPath_ = std::string(endpoint.substr(5)); - setup_unix_domain(); - } else if (absl::StartsWith(endpoint, "udp:")) { - auto pos = 4; - // if the user used udp://foo:1234 instead of udp:foo:1234 - // adjust accordingly - if (endpoint.substr(pos, 2) == "//") { - pos += 2; - } - setup_udp(endpoint.substr(pos)); - } else if (endpoint != "disabled") { - logger_->warn( - "Unknown endpoint: '{}'. Expecting: 'unix:/path/to/socket'" - " or 'udp:hostname:port' - Will not send metrics", - std::string(endpoint)); - setup_nop_sender(); - } -} - -void SpectatordPublisher::setup_nop_sender() { - sender_ = [this](std::string_view msg) { logger_->trace("{}", msg); }; -} - -void SpectatordPublisher::local_reconnect(absl::string_view path) { - using endpoint_t = asio::local::datagram_protocol::endpoint; - try { - if (local_socket_.is_open()) { - local_socket_.close(); - } - local_socket_.open(); - local_socket_.connect(endpoint_t(std::string(path))); - } catch (std::exception& e) { - logger_->warn("Unable to connect to {}: {}", std::string(path), e.what()); - } -} - - -bool SpectatordPublisher::try_to_send(const std::string& buffer) { - for (auto i = 0; i < 3; ++i) { - try { - auto sent_bytes = local_socket_.send(asio::buffer(buffer)); - logger_->trace("Sent (local): {} bytes, in total had {}", sent_bytes, - buffer.length()); - return true; - } catch (std::exception& e) { - local_reconnect(this->unixDomainPath_); - logger_->warn("Unable to send {} - attempt {}/3 ({})", buffer, i, e.what()); - } - } - return false; -} - -void SpectatordPublisher::taskThreadFunction() try { - while (shutdown_.load() == false) { - std::string message {}; - { - std::unique_lock lock(mtx_); - cv_sender_.wait(lock, [this] { return buffer_.size() > bytes_to_buffer_ || shutdown_.load();}); - if (shutdown_.load() == true) { - return; - } - message = std::move(buffer_); - buffer_ = std::string(); - buffer_.reserve(bytes_to_buffer_); - } - cv_receiver_.notify_one(); - try_to_send(message); - } -} catch (const std::exception& e) { - logger_->error("Fatal error in message processing thread: {}", e.what()); -} - -void SpectatordPublisher::setup_unix_domain(){ - // Reset connection to the unix domain socket - local_reconnect(this->unixDomainPath_); - if (bytes_to_buffer_ == 0) { - sender_ = [this](std::string_view msg) { - try_to_send(std::string(msg)); - }; - return; - } - else { - sender_ = [this](std::string_view msg) { - unsigned int currentBufferSize = buffer_.size(); - { - std::unique_lock lock(mtx_); - cv_receiver_.wait(lock, [this] { return buffer_.size() <= bytes_to_buffer_ || shutdown_.load(); }); - if (shutdown_.load()) { - return; - } - buffer_.append(msg.data(), msg.size()); - buffer_.append(1, NEW_LINE); - currentBufferSize = buffer_.size(); - } - currentBufferSize > bytes_to_buffer_ ? cv_sender_.notify_one() : cv_receiver_.notify_one(); - }; - this->sendingThread_ = std::thread(&SpectatordPublisher::taskThreadFunction, this); - } -} - -inline asio::ip::udp::endpoint resolve_host_port( - asio::io_context& io_context, // NOLINT - absl::string_view host_port) { - using asio::ip::udp; - udp::resolver resolver{io_context}; - - auto end_host = host_port.find(':'); - if (end_host == std::string_view::npos) { - auto err = fmt::format( - "Unable to parse udp endpoint: '{}'. Expecting hostname:port", - std::string(host_port)); - throw std::runtime_error(err); - } - - auto host = host_port.substr(0, end_host); - auto port = host_port.substr(end_host + 1); - return *resolver.resolve(udp::v6(), std::string(host), std::string(port)); -} - -void SpectatordPublisher::udp_reconnect( - const asio::ip::udp::endpoint& endpoint) { - try { - if (udp_socket_.is_open()) { - udp_socket_.close(); - } - udp_socket_.open(asio::ip::udp::v6()); - udp_socket_.connect(endpoint); - } catch (std::exception& e) { - logger_->warn("Unable to connect to {}: {}", endpoint.address().to_string(), - endpoint.port()); - } -} - -void SpectatordPublisher::setup_udp(absl::string_view host_port) { - auto endpoint = resolve_host_port(io_context_, host_port); - udp_reconnect(endpoint); - sender_ = [endpoint, this](std::string_view msg) { - for (auto i = 0; i < 3; ++i) { - try { - udp_socket_.send(asio::buffer(msg)); - logger_->trace("Sent (udp): {}", msg); - break; - } catch (std::exception& e) { - logger_->warn("Unable to send {} - attempt {}/3", msg, i); - udp_reconnect(endpoint); - } - } - }; -} -} // namespace spectator diff --git a/spectator/publisher.h b/spectator/publisher.h deleted file mode 100644 index 56e37d7..0000000 --- a/spectator/publisher.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "logger.h" -#include "absl/strings/match.h" -#include "absl/strings/string_view.h" -#include - -namespace spectator { - -class SpectatordPublisher { - public: - explicit SpectatordPublisher( - absl::string_view endpoint, - uint32_t bytes_to_buffer = 0, - std::shared_ptr logger = DefaultLogger()); - SpectatordPublisher(const SpectatordPublisher&) = delete; - - ~SpectatordPublisher() { - shutdown_.store(true); - cv_receiver_.notify_all(); - cv_sender_.notify_all(); - if (sendingThread_.joinable()) { - sendingThread_.join(); - } - } - - void send(std::string_view measurement) { sender_(measurement); }; - - void taskThreadFunction(); - bool try_to_send(const std::string& buffer); - - protected: - using sender_fun = std::function; - sender_fun sender_; - - private: - void setup_nop_sender(); - void setup_unix_domain(); - void setup_udp(absl::string_view host_port); - void local_reconnect(absl::string_view path); - void udp_reconnect(const asio::ip::udp::endpoint& endpoint); - - std::shared_ptr logger_; - asio::io_context io_context_; - asio::ip::udp::socket udp_socket_; - asio::local::datagram_protocol::socket local_socket_; - std::string buffer_; - uint32_t bytes_to_buffer_; - - std::thread sendingThread_; - std::mutex mtx_; - std::condition_variable cv_receiver_; - std::condition_variable cv_sender_; - std::string unixDomainPath_; - std::atomic shutdown_{false}; -}; - -} // namespace spectator diff --git a/spectator/publisher_test.cc b/spectator/publisher_test.cc deleted file mode 100644 index 0358687..0000000 --- a/spectator/publisher_test.cc +++ /dev/null @@ -1,166 +0,0 @@ -#include "id.h" -#include "logger.h" -#include "publisher.h" -#include "stateless_meters.h" -#include "test_server.h" -#include -#include -#include - -namespace { - -using spectator::Counter; -using spectator::Id; -using spectator::SpectatordPublisher; -using spectator::Tags; - -TEST(Publisher, Udp) { - // travis does not support udp on its container - if (std::getenv("TRAVIS_COMPILER") == nullptr) { - TestUdpServer server; - server.Start(); - auto logger = spectator::DefaultLogger(); - logger->info("Udp Server started on port {}", server.GetPort()); - - SpectatordPublisher publisher{ - fmt::format("udp:localhost:{}", server.GetPort()), 0}; - Counter c{std::make_shared("counter", Tags{}), &publisher}; - c.Increment(); - c.Add(2); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - auto msgs = server.GetMessages(); - server.Stop(); - std::vector expected{"c:counter:1", "c:counter:2"}; - EXPECT_EQ(server.GetMessages(), expected); - } -} - -const char* first_not_null(char* a, const char* b) { - if (a != nullptr) return a; - return b; -} - -TEST(Publisher, UnixNoBuffer) { - auto logger = spectator::DefaultLogger(); - const auto* dir = first_not_null(std::getenv("TMPDIR"), "/tmp"); - auto path = fmt::format("{}/testserver.{}", dir, getpid()); - TestUnixServer server{path}; - server.Start(); - logger->info("Unix Server started on path {}", path); - SpectatordPublisher publisher{fmt::format("unix:{}", path), 0}; - Counter c{std::make_shared("counter", Tags{}), &publisher}; - c.Increment(); - c.Add(2); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - auto msgs = server.GetMessages(); - server.Stop(); - unlink(path.c_str()); - std::vector expected{"c:counter:1", "c:counter:2"}; - EXPECT_EQ(msgs, expected); -} - -TEST(Publisher, UnixBuffer) { - auto logger = spectator::DefaultLogger(); - const auto* dir = first_not_null(std::getenv("TMPDIR"), "/tmp"); - auto path = fmt::format("{}/testserver.{}", dir, getpid()); - TestUnixServer server{path}; - server.Start(); - logger->info("Unix Server started on path {}", path); - // Do not send until we buffer 32 bytes of data. - SpectatordPublisher publisher{fmt::format("unix:{}", path), 32}; - Counter c{std::make_shared("counter", Tags{}), &publisher}; - c.Increment(); - c.Increment(); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - auto msgs = server.GetMessages(); - std::vector emptyVector {}; - EXPECT_EQ(msgs, emptyVector); - c.Increment(); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - msgs = server.GetMessages(); - std::vector expected{"c:counter:1\nc:counter:1\nc:counter:1\n"}; - EXPECT_EQ(msgs, expected); - server.Stop(); - unlink(path.c_str()); -} - -TEST(Publisher, Nop) { - SpectatordPublisher publisher{"", 0}; - Counter c{std::make_shared("counter", Tags{}), &publisher}; - c.Increment(); - c.Add(2); -} - -TEST(Publisher, MultiThreadedCounters) { - auto logger = spectator::DefaultLogger(); - const auto* dir = first_not_null(std::getenv("TMPDIR"), "/tmp"); - auto path = fmt::format("{}/testserver.{}", dir, getpid()); - TestUnixServer server{path}; - server.Start(); - logger->info("Unix Server started on path {}", path); - - // Create publisher with a small buffer size to ensure flushing - SpectatordPublisher publisher{fmt::format("unix:{}", path), 50}; - - // Number of threads and counters to create - const int numThreads = 4; - const int countersPerThread = 3; - const int incrementsPerCounter = 5; - - // Function for worker threads - auto worker = [&](int threadId) { - // Create several counters per thread with unique names - for (int i = 0; i < countersPerThread; i++) { - std::string counterName = fmt::format("counter.thread{}.{}", threadId, i); - Counter counter(std::make_shared(counterName, Tags{}), &publisher); - - // Increment each counter multiple times - for (int j = 0; j < incrementsPerCounter; j++) { - counter.Increment(); - } - } - }; - - // Start worker threads - std::vector threads; - for (int i = 0; i < numThreads; i++) { - threads.emplace_back(worker, i); - } - - // Wait for all threads to complete - for (auto& t : threads) { - t.join(); - } - - // Give some time for messages to be sent - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - // Check messages - auto msgs = server.GetMessages(); - EXPECT_FALSE(msgs.empty()); - - // Verify total number of increments - int expectedIncrements = numThreads * countersPerThread * incrementsPerCounter; - int actualIncrements = 0; - - // Verify every string in msgs follows the form counter.thread. - std::regex counter_regex(R"(c:counter\.thread\d+\.\d+:1)"); - for (const auto& msg : msgs) { - std::stringstream ss(msg); - std::string line; - while (std::getline(ss, line)) { - if (!line.empty()) { - EXPECT_TRUE(std::regex_match(line, counter_regex)) - << "Unexpected counter format: " << line; - actualIncrements++; - } - } - } - - EXPECT_EQ(actualIncrements, expectedIncrements); - - server.Stop(); - unlink(path.c_str()); -} - -} // namespace diff --git a/spectator/registry.h b/spectator/registry.h deleted file mode 100644 index 9a8e50d..0000000 --- a/spectator/registry.h +++ /dev/null @@ -1,356 +0,0 @@ -#pragma once - -#include "absl/container/flat_hash_map.h" -#include "absl/synchronization/mutex.h" -#include "config.h" -#include "logger.h" -#include "stateful_meters.h" -#include "stateless_meters.h" -#include "publisher.h" - -namespace spectator { - -// A registry for tests -// This is a stateful registry that will keep references to all registered -// meters and allows users to fetch the measurements at a later point - -namespace detail { -inline void log_type_error(MeterType old_type, MeterType new_type, - const Id& id) { - DefaultLogger()->warn( - "Attempting to register {} as a {} but was previously registered as a {}", - id, new_type, old_type); -} -} // namespace detail - -template -struct single_table_state { - using types = Types; - - template - std::shared_ptr get_or_create(IdPtr id, Args&&... args) { - auto new_meter = - std::make_shared(std::move(id), std::forward(args)...); - absl::MutexLock lock(&mutex_); - auto it = meters_.find(new_meter->MeterId()); - if (it != meters_.end()) { - // already exists, we need to ensure the existing type - // matches the new meter type, otherwise we need to notify the user - // of the error - auto& old_meter = it->second; - if (old_meter->GetType() != new_meter->GetType()) { - detail::log_type_error(old_meter->GetType(), new_meter->GetType(), - *new_meter->MeterId()); - // this is not registered therefore no measurements - // will be reported - return new_meter; - } else { - return std::static_pointer_cast(old_meter); - } - } - - meters_.emplace(new_meter->MeterId(), new_meter); - return new_meter; - } - - auto get_age_gauge(IdPtr id) { - return get_or_create(std::move(id)); - } - - auto get_counter(IdPtr id) { - return get_or_create(std::move(id)); - } - - auto get_ds(IdPtr id) { - return get_or_create(std::move(id)); - } - - auto get_gauge(IdPtr id) { - return get_or_create(std::move(id)); - } - - auto get_gauge_ttl(IdPtr id, unsigned int ttl_seconds) { - return get_or_create(std::move(id), ttl_seconds); - } - - auto get_max_gauge(IdPtr id) { - return get_or_create(std::move(id)); - } - - auto get_monotonic_counter(IdPtr id) { - return get_or_create(std::move(id)); - } - - auto get_monotonic_counter_uint(IdPtr id) { - return get_or_create(std::move(id)); - } - - auto get_perc_ds(IdPtr id, int64_t min, int64_t max) { - return get_or_create(std::move(id), min, max); - } - - auto get_perc_timer(IdPtr id, std::chrono::nanoseconds min, - std::chrono::nanoseconds max) { - return get_or_create(std::move(id), min, max); - } - - auto get_timer(IdPtr id) { - return get_or_create(std::move(id)); - } - - auto measurements() { - std::vector result; - - absl::MutexLock lock(&mutex_); - result.reserve(meters_.size() * 2); - for (auto& m : meters_) { - m.second->Measure(&result); - } - return result; - } - - absl::Mutex mutex_; - // use a single table, so we can easily check whether a meter - // was previously registered as a different type - absl::flat_hash_map, std::hash, - std::equal_to> - meters_ ABSL_GUARDED_BY(mutex_); -}; - -template -class base_registry { - public: - using logger_ptr = std::shared_ptr; - using age_gauge_t = typename Types::age_gauge_t; - using age_gauge_ptr = std::shared_ptr; - using counter_t = typename Types::counter_t; - using counter_ptr = std::shared_ptr; - using dist_summary_t = typename Types::ds_t; - using dist_summary_ptr = std::shared_ptr; - using gauge_t = typename Types::gauge_t; - using gauge_ptr = std::shared_ptr; - using max_gauge_t = typename Types::max_gauge_t; - using max_gauge_ptr = std::shared_ptr; - using monotonic_counter_t = typename Types::monotonic_counter_t; - using monotonic_counter_ptr = std::shared_ptr; - using monotonic_counter_uint_t = typename Types::monotonic_counter_uint_t; - using monotonic_counter_uint_ptr = std::shared_ptr; - using perc_dist_summary_t = typename Types::perc_ds_t; - using perc_dist_summary_ptr = std::shared_ptr; - using perc_timer_t = typename Types::perc_timer_t; - using perc_timer_ptr = std::shared_ptr; - using timer_t = typename Types::timer_t; - using timer_ptr = std::shared_ptr; - - explicit base_registry(logger_ptr logger = DefaultLogger()) - : logger_(std::move(logger)) {} - - auto GetAgeGauge(const IdPtr& id) { - return state_.get_age_gauge(final_id(id)); - } - auto GetAgeGauge(absl::string_view name, Tags tags = {}) { - return GetAgeGauge(Id::of(name, std::move(tags))); - } - - auto GetCounter(const IdPtr& id) { - return state_.get_counter(final_id(id)); - } - auto GetCounter(absl::string_view name, Tags tags = {}) { - return GetCounter(Id::of(name, std::move(tags))); - } - - auto GetDistributionSummary(const IdPtr& id) { - return state_.get_ds(final_id(id)); - } - auto GetDistributionSummary(absl::string_view name, Tags tags = {}) { - return GetDistributionSummary(Id::of(name, std::move(tags))); - } - - auto GetGauge(const IdPtr& id) { - return state_.get_gauge(final_id(id)); - } - auto GetGauge(absl::string_view name, Tags tags = {}) { - return GetGauge(Id::of(name, std::move(tags))); - } - - auto GetGaugeTTL(const IdPtr& id, unsigned int ttl_seconds) { - return state_.get_gauge_ttl(final_id(id), ttl_seconds); - } - - auto GetGaugeTTL(absl::string_view name, unsigned int ttl_seconds, Tags tags = {}) { - return GetGaugeTTL(Id::of(name, std::move(tags)), ttl_seconds); - } - - auto GetMaxGauge(const IdPtr& id) { - return state_.get_max_gauge(final_id(id)); - } - auto GetMaxGauge(absl::string_view name, Tags tags = {}) { - return GetMaxGauge(Id::of(name, std::move(tags))); - } - - auto GetMonotonicCounter(const IdPtr& id) { - return state_.get_monotonic_counter(final_id(id)); - } - auto GetMonotonicCounter(absl::string_view name, Tags tags = {}) { - return GetMonotonicCounter(Id::of(name, std::move(tags))); - } - - auto GetMonotonicCounterUint(const IdPtr& id) { - return state_.get_monotonic_counter_uint(final_id(id)); - } - auto GetMonotonicCounterUint(absl::string_view name, Tags tags = {}) { - return GetMonotonicCounterUint(Id::of(name, std::move(tags))); - } - - auto GetPercentileDistributionSummary(const IdPtr& id, int64_t min, int64_t max) { - return state_.get_perc_ds(final_id(id), min, max); - } - auto GetPercentileDistributionSummary(absl::string_view name, int64_t min, int64_t max) { - return GetPercentileDistributionSummary(Id::of(name), min, max); - } - auto GetPercentileDistributionSummary(absl::string_view name, Tags tags, - int64_t min, int64_t max) { - return GetPercentileDistributionSummary(Id::of(name, std::move(tags)), min, max); - } - - auto GetPercentileTimer(const IdPtr& id, absl::Duration min, absl::Duration max) { - return state_.get_perc_timer(final_id(id), min, max); - } - auto GetPercentileTimer(const IdPtr& id, std::chrono::nanoseconds min, - std::chrono::nanoseconds max) { - return state_.get_perc_timer(final_id(id), absl::FromChrono(min), absl::FromChrono(max)); - } - auto GetPercentileTimer(absl::string_view name, absl::Duration min, absl::Duration max) { - return GetPercentileTimer(Id::of(name), min, max); - } - auto GetPercentileTimer(absl::string_view name, Tags tags, - absl::Duration min, absl::Duration max) { - return GetPercentileTimer(Id::of(name, std::move(tags)), min, max); - } - auto GetPercentileTimer(absl::string_view name, - std::chrono::nanoseconds min, std::chrono::nanoseconds max) { - return GetPercentileTimer(Id::of(name), absl::FromChrono(min), absl::FromChrono(max)); - } - auto GetPercentileTimer(absl::string_view name, Tags tags, - std::chrono::nanoseconds min, std::chrono::nanoseconds max) { - return GetPercentileTimer(Id::of(name, std::move(tags)), absl::FromChrono(min), - absl::FromChrono(max)); - } - - auto GetTimer(const IdPtr& id) { - return state_.get_timer(final_id(id)); - } - auto GetTimer(absl::string_view name, Tags tags = {}) { - return GetTimer(Id::of(name, std::move(tags))); - } - - auto Measurements() { return state_.measurements(); } - - protected: - logger_ptr logger_; - State state_; - Tags extra_tags_; - - // final Id after adding extra_tags_ if any - IdPtr final_id(const IdPtr& id) { - if (extra_tags_.size() > 0) { - return id->WithTags(extra_tags_); - } - return id; - } -}; - -template -struct stateless_types { - using counter_t = Counter; - using ds_t = DistributionSummary; - using gauge_t = Gauge; - using max_gauge_t = MaxGauge; - using age_gauge_t = AgeGauge; - using monotonic_counter_t = MonotonicCounter; - using monotonic_counter_uint_t = MonotonicCounterUint; - using perc_timer_t = PercentileTimer; - using perc_ds_t = PercentileDistributionSummary; - using timer_t = Timer; - using publisher_t = Pub; -}; - -template -struct stateless { - using types = Types; - std::unique_ptr publisher; - - auto get_age_gauge(IdPtr id) { - return std::make_shared(std::move(id), publisher.get()); - } - - auto get_counter(IdPtr id) { - return std::make_shared(std::move(id), publisher.get()); - } - - auto get_ds(IdPtr id) { - return std::make_shared(std::move(id), publisher.get()); - } - - auto get_gauge(IdPtr id) { - return std::make_shared(std::move(id), publisher.get()); - } - - auto get_gauge_ttl(IdPtr id, unsigned int ttl_seconds) { - return std::make_shared(std::move(id), publisher.get(), ttl_seconds); - } - - auto get_max_gauge(IdPtr id) { - return std::make_shared(std::move(id), publisher.get()); - } - - auto get_monotonic_counter(IdPtr id) { - return std::make_shared(std::move(id), publisher.get()); - } - - auto get_monotonic_counter_uint(IdPtr id) { - return std::make_shared(std::move(id), - publisher.get()); - } - - auto get_perc_ds(IdPtr id, int64_t min, int64_t max) { - return std::make_shared(std::move(id), publisher.get(), min, max); - } - - auto get_perc_timer(IdPtr id, absl::Duration min, absl::Duration max) { - return std::make_shared(std::move(id), publisher.get(), min, max); - } - - auto get_timer(IdPtr id) { - return std::make_shared(std::move(id), publisher.get()); - } - - auto measurements() { return std::vector{}; } -}; - -/// A stateless registry that sends all meter activity immediately -/// to a spectatord agent -class SpectatordRegistry - : public base_registry>> { - public: - using types = stateless_types; - explicit SpectatordRegistry(const Config& config, logger_ptr logger) - : base_registry>>( - std::move(logger)) { - extra_tags_ = Tags::from(config.common_tags); - state_.publisher = - std::make_unique(config.endpoint, config.bytes_to_buffer, logger_); - } -}; - -/// A Registry that can be used for tests. It keeps state about which meters -/// have been registered, and can report the measurements from all the -/// registered meters -struct TestRegistry : base_registry> { - using types = stateful_meters; -}; - -/// The default registry -using Registry = SpectatordRegistry; - -} // namespace spectator diff --git a/spectator/src/registry.cpp b/spectator/src/registry.cpp new file mode 100644 index 0000000..314fb17 --- /dev/null +++ b/spectator/src/registry.cpp @@ -0,0 +1,129 @@ +#include + +Registry::Registry(const Config &config) : m_config(config) +{ + Writer::Initialize(config.GetWriterType()); +} + +Registry::~Registry() +{ + // No need to close Writer here as it's a singleton + // and will live beyond Registry instances +} + + +MeterId Registry::new_id(const std::string &name, const std::unordered_map &tags) const +{ + MeterId new_meter_id(name, tags); + + if (this->m_config.GetExtraTags().empty() == true) + { + return new_meter_id; + } + else + { + return new_meter_id.WithTags(this->m_config.GetExtraTags()); + } +} + +AgeGauge Registry::age_gauge(const std::string &name, const std::unordered_map &tags) +{ + return AgeGauge(new_id(name, tags)); +} + +AgeGauge Registry::age_gauge_with_id(const MeterId &meter_id) +{ + return AgeGauge(meter_id); +} + +Counter Registry::counter(const std::string &name, const std::unordered_map &tags) +{ + return Counter(new_id(name, tags)); +} + +Counter Registry::counter_with_id(const MeterId &meter_id) +{ + return Counter(meter_id); +} + +DistributionSummary Registry::distribution_summary(const std::string &name, const std::unordered_map &tags) +{ + return DistributionSummary(new_id(name, tags)); +} + +DistributionSummary Registry::distribution_summary_with_id(const MeterId &meter_id) +{ + return DistributionSummary(meter_id); +} + +Gauge Registry::gauge(const std::string &name, const std::unordered_map &tags, + const std::optional &ttl_seconds) +{ + return Gauge(new_id(name, tags), ttl_seconds); +} + +Gauge Registry::gauge_with_id(const MeterId &meter_id, const std::optional &ttl_seconds) +{ + return Gauge(meter_id, ttl_seconds); +} + +MaxGauge Registry::max_gauge(const std::string &name, const std::unordered_map &tags) +{ + return MaxGauge(new_id(name, tags)); +} + +MaxGauge Registry::max_gauge_with_id(const MeterId &meter_id) +{ + return MaxGauge(meter_id); +} + +MonotonicCounter Registry::monotonic_counter(const std::string &name, const std::unordered_map &tags) +{ + return MonotonicCounter(new_id(name, tags)); +} + +MonotonicCounter Registry::monotonic_counter_with_id(const MeterId &meter_id) +{ + return MonotonicCounter(meter_id); +} + +MonotonicCounterUint Registry::monotonic_counter_uint(const std::string &name, const std::unordered_map &tags) +{ + return MonotonicCounterUint(new_id(name, tags)); +} + +MonotonicCounterUint Registry::monotonic_counter_uint_with_id(const MeterId &meter_id) +{ + return MonotonicCounterUint(meter_id); +} + +PercentileDistributionSummary Registry::pct_distribution_summary(const std::string &name, + const std::unordered_map &tags) +{ + return PercentileDistributionSummary(new_id(name, tags)); +} + +PercentileDistributionSummary Registry::pct_distribution_summary_with_id(const MeterId &meter_id) +{ + return PercentileDistributionSummary(meter_id); +} + +PercentileTimer Registry::pct_timer(const std::string &name, const std::unordered_map &tags) +{ + return PercentileTimer(new_id(name, tags)); +} + +PercentileTimer Registry::pct_timer_with_id(const MeterId &meter_id) +{ + return PercentileTimer(meter_id); +} + +Timer Registry::timer(const std::string &name, const std::unordered_map &tags) +{ + return Timer(new_id(name, tags)); +} + +Timer Registry::timer_with_id(const MeterId &meter_id) +{ + return Timer(meter_id); +} \ No newline at end of file diff --git a/spectator/stateful_meters.h b/spectator/stateful_meters.h deleted file mode 100644 index deacb1a..0000000 --- a/spectator/stateful_meters.h +++ /dev/null @@ -1,299 +0,0 @@ -#pragma once - -#include "id.h" -#include "measurement.h" -#include "meter_type.h" - -namespace spectator { - -namespace detail { -/// Atomically add a delta to an atomic double -/// equivalent to fetch_add for integer types -inline void add_double(std::atomic* n, double delta) { - double current; - do { - current = n->load(std::memory_order_relaxed); - } while (!n->compare_exchange_weak( - current, n->load(std::memory_order_relaxed) + delta)); -} - -/// Atomically set the max value of an atomic number -template -inline void update_max(std::atomic* n, T value) { - T current; - do { - current = n->load(std::memory_order_relaxed); - } while (value > current && !n->compare_exchange_weak(current, value)); -} -} // namespace detail - -class StatefulMeter { - public: - explicit StatefulMeter(IdPtr id) : id_{std::move(id)} {} - StatefulMeter(const StatefulMeter&) = default; - virtual ~StatefulMeter() = default; - virtual void Measure(std::vector* measurements) = 0; - [[nodiscard]] virtual MeterType GetType() const = 0; - [[nodiscard]] IdPtr MeterId() const { return id_; } - - protected: - IdPtr id_; -}; - -template -class TestDistribution : public StatefulMeter { - public: - explicit TestDistribution(IdPtr id) : StatefulMeter(std::move(id)) {} - - int64_t Count() const { return count_; } - - double TotalAmount() const { return total_; } - - MeterType GetType() const override { return DistType::meter_type; } - - void Measure(std::vector* measurements) override { - auto cnt = count_.exchange(0); - if (cnt == 0) { - return; - } - auto total = total_.exchange(0); - auto t_sq = totalSq_.exchange(0); - auto mx = max_.exchange(0); - measurements->emplace_back(id_->WithStat(DistType::total_name), total); - measurements->emplace_back(id_->WithStat("totalOfSquares"), t_sq); - measurements->emplace_back(id_->WithStat("max"), mx); - measurements->emplace_back(id_->WithStat("count"), cnt); - } - - protected: - void record(double amount) { - if (amount >= 0) { - count_.fetch_add(1); - detail::add_double(&total_, amount); - detail::add_double(&totalSq_, amount * amount); - detail::update_max(&max_, amount); - } - } - - private: - std::atomic count_ = 0; - std::atomic total_ = 0; - std::atomic totalSq_ = 0; - std::atomic max_ = 0; -}; - -struct timer_distribution { - static constexpr auto meter_type = MeterType::Timer; - static constexpr auto total_name = "totalTime"; -}; - -struct summary_distribution { - static constexpr auto meter_type = MeterType::DistSummary; - static constexpr auto total_name = "totalAmount"; -}; - -class StatefulAgeGauge : public StatefulMeter { - public: - explicit StatefulAgeGauge(IdPtr id) : StatefulMeter(std::move(id)) {} - - [[nodiscard]] double Get() const { return value_; } - - MeterType GetType() const override { return MeterType::AgeGauge; } - - void Set(double amount) { value_ = amount; } - - void Measure(std::vector* measurements) override { - auto v = value_.exchange(kNaN); - if (std::isnan(v)) { - return; - } - measurements->emplace_back(Id::WithDefaultStat(id_, "gauge"), v); - } - - private: - static constexpr auto kNaN = std::numeric_limits::quiet_NaN(); - std::atomic value_ = kNaN; -}; - -class StatefulCounter : public StatefulMeter { - public: - explicit StatefulCounter(IdPtr id) : StatefulMeter(std::move(id)) {} - - [[nodiscard]] double Count() const { return count_; }; - - MeterType GetType() const override { return MeterType::Counter; } - - void Add(double delta) { - if (delta > 0) { - detail::add_double(&count_, delta); - } - } - - void Increment() { Add(1); } - - void Measure(std::vector* measurements) override { - auto count = count_.exchange(0.0); - if (count > 0) { - measurements->emplace_back(Id::WithDefaultStat(id_, "count"), count); - } - } - - private: - std::atomic count_ = 0.0; -}; - -class StatefulDistSum : public TestDistribution { - public: - explicit StatefulDistSum(IdPtr id): TestDistribution(std::move(id)) {} - - void Record(double amount) { record(amount); } -}; - -class StatefulGauge : public StatefulMeter { - public: - explicit StatefulGauge(IdPtr id) : StatefulMeter(std::move(id)) {} - - [[nodiscard]] double Get() const { return value_; } - - MeterType GetType() const override { return MeterType::Gauge; } - - void Set(double amount) { value_ = amount; } - - void Measure(std::vector* measurements) override { - auto v = value_.exchange(kNaN); - if (std::isnan(v)) { - return; - } - measurements->emplace_back(Id::WithDefaultStat(id_, "gauge"), v); - } - - private: - static constexpr auto kNaN = std::numeric_limits::quiet_NaN(); - std::atomic value_ = kNaN; -}; - -class StatefulMaxGauge : public StatefulMeter { - public: - explicit StatefulMaxGauge(IdPtr id) : StatefulMeter(std::move(id)) {} - - [[nodiscard]] double Get() const { return value_; } - - MeterType GetType() const override { return MeterType::MaxGauge; } - - void Set(double amount) { detail::update_max(&value_, amount); } - - void Update(double amount) { Set(amount); } - - void Measure(std::vector* measurements) override { - auto v = value_.exchange(kMinValue); - if (v == kMinValue) { - return; - } - measurements->emplace_back(Id::WithDefaultStat(id_, "max"), v); - } - - private: - static constexpr auto kMinValue = std::numeric_limits::lowest(); - std::atomic value_ = kMinValue; -}; - -class StatefulMonoCounter : public StatefulMeter { - public: - explicit StatefulMonoCounter(IdPtr id) : StatefulMeter(std::move(id)) {} - - MeterType GetType() const override { return MeterType::MonotonicCounter; } - - [[nodiscard]] double Delta() const { return value_ - prev_value_; } - - void Set(double amount) { value_ = amount; } - - void Measure(std::vector* measurements) override { - auto delta = Delta(); - prev_value_ = value_.load(); - if (delta > 0) { - measurements->emplace_back(id_->WithStat("count"), delta); - } - } - - private: - static constexpr auto kNaN = std::numeric_limits::quiet_NaN(); - std::atomic value_ = kNaN; - std::atomic prev_value_ = kNaN; -}; - -class StatefulMonoCounterUint : public StatefulMeter { - public: - explicit StatefulMonoCounterUint(IdPtr id) : StatefulMeter(std::move(id)) {} - - MeterType GetType() const override { return MeterType::MonotonicCounterUint; } - - [[nodiscard]] double Delta() const { - if (value_ < prev_value_) { - return kMax - prev_value_ + value_ + 1; - } else { - return value_ - prev_value_; - } - } - - void Set(uint64_t amount) { value_ = amount; } - - void Measure(std::vector* measurements) override { - auto delta = Delta(); - prev_value_ = value_.load(); - if (delta > 0) { - measurements->emplace_back(id_->WithStat("count"), delta); - } - } - - private: - static constexpr auto kMax = std::numeric_limits::max(); - std::atomic value_ = 0; - std::atomic prev_value_ = 0; -}; - -class StatefulPercTimer : public StatefulMeter { - public: - StatefulPercTimer(IdPtr id, std::chrono::nanoseconds, std::chrono::nanoseconds) - : StatefulMeter(std::move(id)) {} - - [[nodiscard]] MeterType GetType() const override { return MeterType::PercentileTimer; } - - void Measure(std::vector*) override {} - - private: -}; - -class StatefulPercDistSum : public StatefulMeter { - public: - StatefulPercDistSum(IdPtr id, int64_t, int64_t): StatefulMeter(std::move(id)) {} - - [[nodiscard]] MeterType GetType() const override { - return MeterType::PercentileDistSummary; - } - - void Measure(std::vector*) override {} -}; - -class StatefulTimer : public TestDistribution { - public: - explicit StatefulTimer(IdPtr id): TestDistribution(std::move(id)) {} - - void Record(absl::Duration amount) { record(absl::ToDoubleSeconds(amount)); } - - void Record(std::chrono::nanoseconds amount) { Record(absl::FromChrono(amount)); } -}; - -struct stateful_meters { - using counter_t = StatefulCounter; - using ds_t = StatefulDistSum; - using gauge_t = StatefulGauge; - using max_gauge_t = StatefulMaxGauge; - using age_gauge_t = StatefulAgeGauge; - using monotonic_counter_t = StatefulMonoCounter; - using monotonic_counter_uint_t = StatefulMonoCounterUint; - using perc_timer_t = StatefulPercTimer; - using perc_ds_t = StatefulPercDistSum; - using timer_t = StatefulTimer; -}; - -} // namespace spectator diff --git a/spectator/stateful_test.cc b/spectator/stateful_test.cc deleted file mode 100644 index 2d1134a..0000000 --- a/spectator/stateful_test.cc +++ /dev/null @@ -1,35 +0,0 @@ -#include "registry.h" -#include - -namespace { - -TEST(Stateful, Counter) { - spectator::TestRegistry testRegistry; - - auto ctr = testRegistry.GetCounter( - std::make_shared("foo", spectator::Tags())); - ctr->Increment(); - - EXPECT_EQ(testRegistry.Measurements().size(), 1); - EXPECT_EQ(testRegistry.Measurements().size(), 0); -} - -TEST(Stateful, Timer) { - spectator::TestRegistry testRegistry; - testRegistry.GetTimer("name")->Record(absl::Seconds(0.5)); - EXPECT_EQ(testRegistry.Measurements().size(), 4); -} - -TEST(Stateful, Gauge) { - spectator::TestRegistry testRegistry; - testRegistry.GetGauge("name")->Set(1); - EXPECT_EQ(testRegistry.Measurements().size(), 1); -} - -TEST(Stateful, SameMeter) { - spectator::TestRegistry registry; - registry.GetCounter("foo")->Add(2); - EXPECT_EQ(registry.GetCounter("foo")->Count(), 2); -} - -} // namespace \ No newline at end of file diff --git a/spectator/stateless_meters.h b/spectator/stateless_meters.h deleted file mode 100644 index fdad8e9..0000000 --- a/spectator/stateless_meters.h +++ /dev/null @@ -1,256 +0,0 @@ -#pragma once -#include "id.h" -#include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" -#include "absl/time/time.h" - -namespace spectator { - -namespace detail { - -#include "valid_chars.inc" - -inline std::string as_string(std::string_view v) { - return {v.data(), v.size()}; -} - -inline bool contains_non_atlas_char(const std::string& input) { - return std::any_of(input.begin(), input.end(), [](char c) { return !kAtlasChars[c]; }); -} - -inline std::string replace_invalid_characters(const std::string& input) { - if (contains_non_atlas_char(input)) { - std::string result{input}; - for (char &c : result) { - if (!kAtlasChars[c]) { - c = '_'; - } - } - return result; - } else { - return input; - } -} - -inline std::string create_prefix(const Id& id, std::string_view type_name) { - std::string res = as_string(type_name) + ":" + replace_invalid_characters(id.Name()); - for (const auto& tags : id.GetTags()) { - auto first = replace_invalid_characters(tags.first); - auto second = replace_invalid_characters(tags.second); - absl::StrAppend(&res, ",", first, "=", second); - } - - absl::StrAppend(&res, ":"); - return res; -} - -template -T restrict(T amount, T min, T max) { - auto r = amount; - if (r > max) { - r = max; - } else if (r < min) { - r = min; - } - return r; -} -} // namespace detail - -template -class StatelessMeter { - public: - StatelessMeter(IdPtr id, Pub* publisher) - : id_(std::move(id)), publisher_(publisher) { - assert(publisher_ != nullptr); - } - virtual ~StatelessMeter() = default; - std::string GetPrefix() { - if (value_prefix_.empty()) { - value_prefix_ = detail::create_prefix(*id_, Type()); - } - return value_prefix_; - } - [[nodiscard]] IdPtr MeterId() const noexcept { return id_; } - [[nodiscard]] virtual std::string_view Type() = 0; - - protected: - void send(double value) { - if (value_prefix_.empty()) { - value_prefix_ = detail::create_prefix(*id_, Type()); - } - auto msg = absl::StrFormat("%s%f", value_prefix_, value); - // remove trailing zeros and decimal points - msg.erase(msg.find_last_not_of('0') + 1, std::string::npos); - msg.erase(msg.find_last_not_of('.') + 1, std::string::npos); - publisher_->send(msg); - } - - void send_uint(uint64_t value) { - if (value_prefix_.empty()) { - value_prefix_ = detail::create_prefix(*id_, Type()); - } - auto msg = absl::StrFormat("%s%u", value_prefix_, value); - publisher_->send(msg); - } - - private: - IdPtr id_; - Pub* publisher_; - std::string value_prefix_; -}; - -template -class AgeGauge : public StatelessMeter { - public: - AgeGauge(IdPtr id, Pub* publisher) - : StatelessMeter(std::move(id), publisher) {} - void Now() noexcept { this->send(0); } - void Set(double value) noexcept { this->send(value); } - - protected: - std::string_view Type() override { return "A"; } -}; - -template -class Counter : public StatelessMeter { - public: - Counter(IdPtr id, Pub* publisher) - : StatelessMeter(std::move(id), publisher) {} - void Increment() noexcept { this->send(1); }; - void Add(double delta) noexcept { this->send(delta); } - - protected: - std::string_view Type() override { return "c"; } -}; - -template -class DistributionSummary : public StatelessMeter { - public: - DistributionSummary(IdPtr id, Pub* publisher) - : StatelessMeter(std::move(id), publisher) {} - void Record(double amount) noexcept { this->send(amount); } - - protected: - std::string_view Type() override { return "d"; } -}; - -template -class Gauge : public StatelessMeter { - public: - Gauge(IdPtr id, Pub* publisher, unsigned int ttl_seconds = 0) - : StatelessMeter(std::move(id), publisher) { - if (ttl_seconds > 0) { - type_str_ = "g," + std::to_string(ttl_seconds); - } - } - void Set(double value) noexcept { this->send(value); } - - protected: - std::string_view Type() override { return type_str_; } - - private: - std::string type_str_{"g"}; -}; - -template -class MaxGauge : public StatelessMeter { - public: - MaxGauge(IdPtr id, Pub* publisher) - : StatelessMeter(std::move(id), publisher) {} - void Update(double value) noexcept { this->send(value); } - // synonym for Update for consistency with the Gauge interface - void Set(double value) noexcept { this->send(value); } - - protected: - std::string_view Type() override { return "m"; } -}; - -template -class MonotonicCounter : public StatelessMeter { - public: - MonotonicCounter(IdPtr id, Pub* publisher) - : StatelessMeter(std::move(id), publisher) {} - void Set(double amount) noexcept { this->send(amount); } - - protected: - std::string_view Type() override { return "C"; } -}; - -template -class MonotonicCounterUint : public StatelessMeter { - public: - MonotonicCounterUint(IdPtr id, Pub* publisher) - : StatelessMeter(std::move(id), publisher) {} - void Set(uint64_t amount) noexcept { this->send_uint(amount); } - - protected: - std::string_view Type() override { return "U"; } -}; - -template -class PercentileDistributionSummary : public StatelessMeter { - public: - PercentileDistributionSummary(IdPtr id, Pub* publisher, int64_t min, - int64_t max) - : StatelessMeter(std::move(id), publisher), min_{min}, max_{max} {} - - void Record(int64_t amount) noexcept { - this->send(detail::restrict(amount, min_, max_)); - } - - protected: - std::string_view Type() override { return "D"; } - - private: - int64_t min_; - int64_t max_; -}; - -template -class PercentileTimer : public StatelessMeter { - public: - PercentileTimer(IdPtr id, Pub* publisher, absl::Duration min, - absl::Duration max) - : StatelessMeter(std::move(id), publisher), min_(min), max_(max) {} - - PercentileTimer(IdPtr id, Pub* publisher, std::chrono::nanoseconds min, - std::chrono::nanoseconds max) - : PercentileTimer(std::move(id), publisher, absl::FromChrono(min), - absl::FromChrono(max)) {} - - void Record(std::chrono::nanoseconds amount) noexcept { - Record(absl::FromChrono(amount)); - } - - void Record(absl::Duration amount) noexcept { - auto duration = detail::restrict(amount, min_, max_); - this->send(absl::ToDoubleSeconds(duration)); - } - - protected: - std::string_view Type() override { return "T"; } - - private: - absl::Duration min_; - absl::Duration max_; -}; - -template -class Timer : public StatelessMeter { - public: - Timer(IdPtr id, Pub* publisher) - : StatelessMeter(std::move(id), publisher) {} - void Record(std::chrono::nanoseconds amount) noexcept { - Record(absl::FromChrono(amount)); - } - - void Record(absl::Duration amount) noexcept { - auto secs = absl::ToDoubleSeconds(amount); - this->send(secs); - } - - protected: - std::string_view Type() override { return "t"; } -}; - -} // namespace spectator diff --git a/spectator/statelessregistry_test.cc b/spectator/statelessregistry_test.cc deleted file mode 100644 index c161bbd..0000000 --- a/spectator/statelessregistry_test.cc +++ /dev/null @@ -1,219 +0,0 @@ -#include "registry.h" -#include "test_publisher.h" -#include - -namespace { - -using spectator::base_registry; -using spectator::stateless; -using spectator::stateless_types; -using spectator::TestPublisher; - -// A stateless registry that uses a test publisher -class TestStatelessRegistry - : public base_registry>> { - public: - TestStatelessRegistry() { - state_.publisher = std::make_unique(); - } - auto SentMessages() { return state_.publisher->SentMessages(); } - void Reset() { return state_.publisher->Reset(); } - void AddExtraTag(absl::string_view k, absl::string_view v) { - extra_tags_.add(k, v); - } -}; - -TEST(StatelessRegistry, AgeGauge) { - TestStatelessRegistry r; - auto ag = r.GetAgeGauge("foo"); - auto ag2 = r.GetAgeGauge("bar", {{"id", "2"}}); - ag->Now(); - ag2->Set(100); - std::vector expected = {"A:foo:0", "A:bar,id=2:100"}; - EXPECT_EQ(r.SentMessages(), expected); -} - -TEST(StatelessRegistry, Counter) { - TestStatelessRegistry r; - auto c = r.GetCounter("foo"); - c->Increment(); - EXPECT_EQ(r.SentMessages().front(), "c:foo:1"); - - r.Reset(); - c = r.GetCounter("foo", {{"k1", "v1"}}); - c->Add(2); - EXPECT_EQ(r.SentMessages().front(), "c:foo,k1=v1:2"); -} - -TEST(StatelessRegistry, DistSummary) { - TestStatelessRegistry r; - auto ds = r.GetDistributionSummary("foo"); - ds->Record(100); - EXPECT_EQ(r.SentMessages().front(), "d:foo:100"); - - r.Reset(); - ds = r.GetDistributionSummary("bar", {{"k1", "v1"}}); - ds->Record(2); - EXPECT_EQ(r.SentMessages().front(), "d:bar,k1=v1:2"); -} - -TEST(StatelessRegistry, Gauge) { - TestStatelessRegistry r; - auto g = r.GetGauge("foo"); - auto g2 = r.GetGauge("bar", {{"id", "2"}}); - auto g3 = r.GetGaugeTTL("baz", 1); - auto g4 = r.GetGaugeTTL("quux", 2, {{"id", "2"}}); - g->Set(100); - g2->Set(101); - g3->Set(102); - g4->Set(103); - std::vector expected = {"g:foo:100", "g:bar,id=2:101", - "g,1:baz:102", "g,2:quux,id=2:103"}; - EXPECT_EQ(r.SentMessages(), expected); -} - -TEST(StatelessRegistry, MaxGauge) { - TestStatelessRegistry r; - auto m = r.GetMaxGauge("foo"); - auto m2 = r.GetMaxGauge("bar", {{"id", "2"}}); - m->Update(100); - m2->Set(101); - std::vector expected = {"m:foo:100", "m:bar,id=2:101"}; - EXPECT_EQ(r.SentMessages(), expected); -} - -TEST(StatelessRegistry, MonotonicCounter) { - TestStatelessRegistry r; - auto m = r.GetMonotonicCounter("foo"); - auto m2 = r.GetMonotonicCounter("bar", {{"id", "2"}}); - m->Set(101.1); - m2->Set(102.2); - std::vector expected = {"C:foo:101.1", "C:bar,id=2:102.2"}; - EXPECT_EQ(r.SentMessages(), expected); -} - -TEST(StatelessRegistry, MonotonicCounterUint) { - TestStatelessRegistry r; - auto m = r.GetMonotonicCounterUint("foo"); - auto m2 = r.GetMonotonicCounterUint("bar", {{"id", "2"}}); - m->Set(100); - m2->Set(101); - std::vector expected = {"U:foo:100", "U:bar,id=2:101"}; - EXPECT_EQ(r.SentMessages(), expected); -} - -TEST(StatelessRegistry, Timer) { - TestStatelessRegistry r; - auto t = r.GetTimer("foo"); - auto t2 = r.GetTimer("bar", {{"id", "2"}}); - t->Record(std::chrono::microseconds(100)); - t2->Record(absl::Seconds(0.1)); - std::vector expected = {"t:foo:0.0001", "t:bar,id=2:0.1"}; - EXPECT_EQ(r.SentMessages(), expected); -} - -TEST(StatelessRegistry, PercentileTimer) { - TestStatelessRegistry r; - auto t = r.GetPercentileTimer("foo", absl::ZeroDuration(), absl::Seconds(10)); - auto t2 = r.GetPercentileTimer("bar", absl::Milliseconds(1), absl::Seconds(1)); - - t->Record(std::chrono::microseconds(100)); - t2->Record(std::chrono::microseconds(100)); - - t->Record(absl::Seconds(5)); - t2->Record(absl::Seconds(5)); - - t->Record(std::chrono::milliseconds(100)); - t2->Record(std::chrono::milliseconds(100)); - - std::vector expected = {"T:foo:0.0001", "T:bar:0.001", - "T:foo:5", "T:bar:1", - "T:foo:0.1", "T:bar:0.1"}; - EXPECT_EQ(r.SentMessages(), expected); -} - -TEST(StatelessRegistry, PercentileDistributionSummary) { - TestStatelessRegistry r; - auto t = r.GetPercentileDistributionSummary("foo", 0, 1000); - auto t2 = r.GetPercentileDistributionSummary("bar", 10, 100); - - t->Record(5); - t2->Record(5); - - t->Record(500); - t2->Record(500); - - t->Record(50); - t2->Record(50); - - std::vector expected = {"D:foo:5", "D:bar:10", - "D:foo:500", "D:bar:100", - "D:foo:50", "D:bar:50"}; - EXPECT_EQ(r.SentMessages(), expected); -} - -template -void test_meter(T&& m1, T&& m2) { - auto id1 = m1->MeterId(); - auto id2 = m2->MeterId(); - EXPECT_EQ(*id1, *id2); - - spectator::Tags expected{{"x.spectator", "v1"}}; - EXPECT_EQ(id1->GetTags(), expected); -} - -TEST(StatelessRegistry, ExtraTags) { - using spectator::Id; - - TestStatelessRegistry r; - r.AddExtraTag("x.spectator", "v1"); - - // Counters - auto c_name = r.GetCounter("name"); - auto c_id = r.GetCounter(Id::of("name")); - test_meter(c_name, c_id); - - // DistSummaries - auto d_name = r.GetDistributionSummary("ds"); - auto d_id = r.GetDistributionSummary(Id::of("ds")); - test_meter(d_name, d_id); - - // Gauges - auto g_name = r.GetGauge("g"); - auto g_id = r.GetGauge(Id::of("g")); - test_meter(g_name, g_id); - - // MaxGauge - auto mx_name = r.GetMaxGauge("m1"); - auto mx_id = r.GetMaxGauge(Id::of("m1")); - test_meter(mx_name, mx_id); - - // MonoCounter - auto mo_name = r.GetMonotonicCounter("mo1"); - auto mo_id = r.GetMonotonicCounter(Id::of("mo1")); - test_meter(mo_name, mo_id); - - // MonoCounter Uint - auto mo_u_name = r.GetMonotonicCounterUint("mo1"); - auto mo_u_id = r.GetMonotonicCounterUint(Id::of("mo1")); - test_meter(mo_name, mo_id); - - // Pct DistSummaries - auto pds_name = r.GetPercentileDistributionSummary("pds", 0, 100); - auto pds_id = r.GetPercentileDistributionSummary(Id::of("pds"), 0, 100); - test_meter(pds_name, pds_id); - - // Pct Timers - auto pt_name = - r.GetPercentileTimer("t", absl::ZeroDuration(), absl::Seconds(1)); - auto pt_id = - r.GetPercentileTimer(Id::of("t"), absl::ZeroDuration(), absl::Seconds(1)); - test_meter(pt_name, pt_id); - - // Timers - auto t_name = r.GetTimer("t1"); - auto t_id = r.GetTimer(Id::of("t1")); - test_meter(t_name, t_id); -} - -} // namespace diff --git a/spectator/test/test_registry.cpp b/spectator/test/test_registry.cpp new file mode 100644 index 0000000..b3dc4c6 --- /dev/null +++ b/spectator/test/test_registry.cpp @@ -0,0 +1,342 @@ +#include +#include + +#include "../include/registry.h" +#include + +#include + +TEST(RegistryTest, Close) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto c = r.counter("counter"); + c.Increment(); + + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + EXPECT_EQ("c:counter:1.000000", memoryWriter->LastLine()); + + memoryWriter->Close(); + EXPECT_TRUE(memoryWriter->IsEmpty()); +} + +TEST(RegistryTest, AgeGauge) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto g1 = r.age_gauge("age_gauge"); + auto g2 = r.age_gauge("age_gauge", {{"my-tags", "bar"}}); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + EXPECT_TRUE(memoryWriter->IsEmpty()); + + g1.Set(1); + EXPECT_EQ("A:age_gauge:1", memoryWriter->LastLine()); + + g2.Set(2); + EXPECT_EQ("A:age_gauge,my-tags=bar:2", memoryWriter->LastLine()); +} + +TEST(RegistryTest, AgeGaugeWithId) +{ + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto g = r.age_gauge_with_id(r.new_id("age_gauge", {{"my-tags", "bar"}})); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + g.Set(0); + EXPECT_EQ("A:age_gauge,extra-tags=foo,my-tags=bar:0", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); +} + +TEST(RegistryTest, Counter) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto c1 = r.counter("counter"); + auto c2 = r.counter("counter", {{"my-tags", "bar"}}); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + EXPECT_TRUE(memoryWriter->IsEmpty()); + + c1.Increment(); + EXPECT_EQ("c:counter:1.000000", memoryWriter->LastLine()); + + c2.Increment(); + EXPECT_EQ("c:counter,my-tags=bar:1.000000", memoryWriter->LastLine()); + + c1.Increment(2); + EXPECT_EQ("c:counter:2.000000", memoryWriter->LastLine()); + + c2.Increment(2); + EXPECT_EQ("c:counter,my-tags=bar:2.000000", memoryWriter->LastLine()); + + r.counter("counter").Increment(3); + EXPECT_EQ("c:counter:3.000000", memoryWriter->LastLine()); +} + +TEST(RegistryTest, CounterWithId) +{ + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto c = r.counter_with_id(r.new_id("counter", {{"my-tags", "bar"}})); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + c.Increment(); + EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:1.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + + c.Increment(2); + EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:2.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + + r.counter("counter", {{"my-tags", "bar"}}).Increment(3); + EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:3.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); +} + +TEST(RegistryTest, DistributionSummary) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto d = r.distribution_summary("distribution_summary"); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + d.Record(42); + EXPECT_EQ("d:distribution_summary:42", memoryWriter->LastLine()); +} + +TEST(RegistryTest, DistributionSummaryWithId) +{ + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto d = r.distribution_summary_with_id(r.new_id("distribution_summary", {{"my-tags", "bar"}})); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + d.Record(42); + EXPECT_EQ("d:distribution_summary,extra-tags=foo,my-tags=bar:42", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); +} + +TEST(RegistryTest, Gauge) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto g = r.gauge("gauge"); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + g.Set(42); + EXPECT_EQ("g:gauge:42.000000", memoryWriter->LastLine()); +} + +TEST(RegistryTest, GaugeWithId) +{ + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto g = r.gauge_with_id(r.new_id("gauge", {{"my-tags", "bar"}})); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + g.Set(42); + EXPECT_EQ("g:gauge,extra-tags=foo,my-tags=bar:42.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); +} + +TEST(RegistryTest, GaugeWithIdWithTtlSeconds) +{ + // WriterConfig writerConfig(WriterTypes::Memory); + // Config config(writerConfig, {{"extra-tags", "foo"}}); + // auto r = Registry(config); + + // auto g = r.gauge_with_id(r.new_id("gauge", {{"my-tags", "bar"}}), 120); + // EXPECT_TRUE(memoryWriter->IsEmpty()); + + // g->Set(42); + // EXPECT_EQ("g,120:gauge,extra-tags=foo,my-tags=bar:42", memoryWriter->LastLine()); +} + +// TEST_F(RegistryTest, GaugeWithTtlSeconds) { +// WriterConfig writerConfig(WriterTypes::Memory); +// Config config(writerConfig); +// auto r = Registry(config); + +// auto g = r.gauge("gauge", 120); +// EXPECT_TRUE(memoryWriter->IsEmpty()); + +// g.Set(42); +// EXPECT_EQ("g,120:gauge:42", memoryWriter->LastLine()); +// } + +TEST(RegistryTest, MaxGauge) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto g = r.max_gauge("max_gauge"); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + g.Set(42); + EXPECT_EQ("m:max_gauge:42.000000", memoryWriter->LastLine()); +} + +TEST(RegistryTest, MaxGaugeWithId) +{ + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto g = r.max_gauge_with_id(r.new_id("max_gauge", {{"my-tags", "bar"}})); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + g.Set(42); + EXPECT_EQ("m:max_gauge,extra-tags=foo,my-tags=bar:42.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); +} + +TEST(RegistryTest, MonotonicCounter) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto c = r.monotonic_counter("monotonic_counter"); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + c.Set(42); + EXPECT_EQ("C:monotonic_counter:42.000000", memoryWriter->LastLine()); +} + +TEST(RegistryTest, MonotonicCounterWithId) +{ + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto c = r.monotonic_counter_with_id(r.new_id("monotonic_counter", {{"my-tags", "bar"}})); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + c.Set(42); + EXPECT_EQ("C:monotonic_counter,extra-tags=foo,my-tags=bar:42.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); +} + +TEST(RegistryTest, MonotonicCounterUint) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto c = r.monotonic_counter_uint("monotonic_counter_uint"); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + c.Set(42); + EXPECT_EQ("U:monotonic_counter_uint:42", memoryWriter->LastLine()); +} + +TEST(RegistryTest, MonotonicCounterUintWithId) +{ + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto c = r.monotonic_counter_uint_with_id(r.new_id("monotonic_counter_uint", {{"my-tags", "bar"}})); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + c.Set(42); + EXPECT_EQ("U:monotonic_counter_uint,extra-tags=foo,my-tags=bar:42", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); +} + +TEST(RegistryTest, NewId) +{ + Config config1(WriterConfig(WriterTypes::Memory)); + auto r1 = Registry(config1); + auto id1 = r1.new_id("id"); + EXPECT_EQ("MeterId(name=id, tags={})", id1.to_string()); + + Config config2(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r2 = Registry(config2); + auto id2 = r2.new_id("id"); + EXPECT_EQ("MeterId(name=id, tags={'extra-tags': 'foo'})", id2.to_string()); +} + +TEST(RegistryTest, PctDistributionSummary) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto d = r.pct_distribution_summary("pct_distribution_summary"); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + d.Record(42); + EXPECT_EQ("D:pct_distribution_summary:42", memoryWriter->LastLine()); +} + +TEST(RegistryTest, PctDistributionSummaryWithId) +{ + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto d = r.pct_distribution_summary_with_id(r.new_id("pct_distribution_summary", {{"my-tags", "bar"}})); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + d.Record(42); + EXPECT_EQ("D:pct_distribution_summary,extra-tags=foo,my-tags=bar:42", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); +} + +TEST(RegistryTest, PctTimer) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto t = r.pct_timer("pct_timer"); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + t.Record(42); + EXPECT_EQ("T:pct_timer:42.000000", memoryWriter->LastLine()); +} + +TEST(RegistryTest, PctTimerWithId) +{ + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto t = r.pct_timer_with_id(r.new_id("pct_timer", {{"my-tags", "bar"}})); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + t.Record(42); + EXPECT_EQ("T:pct_timer,extra-tags=foo,my-tags=bar:42.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); +} + +TEST(RegistryTest, Timer) +{ + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto t = r.timer("timer"); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + t.Record(42); + EXPECT_EQ("t:timer:42.000000", memoryWriter->LastLine()); +} + +TEST(RegistryTest, TimerWithId) +{ + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto t = r.timer_with_id(r.new_id("timer", {{"my-tags", "bar"}})); + EXPECT_TRUE(memoryWriter->IsEmpty()); + + t.Record(42); + EXPECT_EQ("t:timer,extra-tags=foo,my-tags=bar:42.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); +} \ No newline at end of file diff --git a/spectator/test_main.cc b/spectator/test_main.cc deleted file mode 100644 index 90247e1..0000000 --- a/spectator/test_main.cc +++ /dev/null @@ -1,8 +0,0 @@ -#include "backward.hpp" -#include - -int main(int argc, char** argv) { - ::testing::InitGoogleTest(&argc, argv); - backward::SignalHandling sh; - return RUN_ALL_TESTS(); -} diff --git a/spectator/test_publisher.h b/spectator/test_publisher.h deleted file mode 100644 index 78006d5..0000000 --- a/spectator/test_publisher.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "publisher.h" -#include -#include - -namespace spectator { -class TestPublisher { - public: - void send(std::string_view msg) { messages.emplace_back(msg); } - std::vector SentMessages() { return messages; } - void Reset() { messages.clear(); } - - private: - std::vector messages; -}; -} // namespace spectator \ No newline at end of file diff --git a/spectator/test_server.h b/spectator/test_server.h deleted file mode 100644 index 1c3b29e..0000000 --- a/spectator/test_server.h +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include -#include "logger.h" - -template -class TestServer { - public: - explicit TestServer(typename T::endpoint endpoint) - : socket_{context_, endpoint} {} - void Start() { - start_receiving(); - runner = std::thread([this]() { context_.run(); }); - } - - void Stop() { - spectator::DefaultLogger()->info("Stopping test server"); - context_.stop(); - runner.join(); - } - - ~TestServer() { - if (runner.joinable()) { - spectator::DefaultLogger()->info( - "Test server runner was not stopped properly"); - Stop(); - } - } - - void Reset() { msgs.clear(); } - - [[nodiscard]] std::vector GetMessages() const { return msgs; } - - protected: - std::thread runner; - asio::io_context context_{}; - typename T::socket socket_; - char buf[32768]; - std::vector msgs; - - void start_receiving() { - socket_.async_receive( - asio::buffer(buf, sizeof buf), - [this](const std::error_code& err, size_t bytes_transferred) { - assert(!err); - msgs.emplace_back(std::string(buf, bytes_transferred)); - start_receiving(); - }); - } -}; - -class TestUdpServer : public TestServer { - public: - TestUdpServer() - : TestServer{asio::ip::udp::endpoint{asio::ip::udp::v6(), 0}}, - port_{socket_.local_endpoint().port()} {} - - [[nodiscard]] int GetPort() const { return port_; } - - private: - int port_; -}; - -class TestUnixServer : public TestServer { - public: - explicit TestUnixServer(std::string_view path) - : TestServer{asio::local::datagram_protocol::endpoint{path}} {} -}; diff --git a/spectator/timer_test.cc b/spectator/timer_test.cc deleted file mode 100644 index 0f380e5..0000000 --- a/spectator/timer_test.cc +++ /dev/null @@ -1,32 +0,0 @@ -#include "stateless_meters.h" -#include "test_publisher.h" -#include - -namespace { -using spectator::Id; -using spectator::Tags; -using spectator::TestPublisher; -using spectator::Timer; - -TEST(Timer, Record) { - TestPublisher publisher; - auto id = std::make_shared("t.name", Tags{}); - auto id2 = std::make_shared("t2", Tags{{"key", "val"}}); - Timer t{id, &publisher}; - Timer t2{id2, &publisher}; - t.Record(std::chrono::milliseconds(1)); - t2.Record(absl::Seconds(0.1)); - t2.Record(absl::Microseconds(500)); - std::vector expected = {"t:t.name:0.001", "t:t2,key=val:0.1", "t:t2,key=val:0.0005"}; - EXPECT_EQ(publisher.SentMessages(), expected); -} - -TEST(Timer, InvalidTags) { - TestPublisher publisher; - // test with a single tag, because tags order is not guaranteed in a flat_hash_map - auto id = std::make_shared("timer`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo", - Tags{{"tag1,:=", "value1,:="}}); - Timer t{id, &publisher}; - EXPECT_EQ("t:timer______^____-_~______________.___foo,tag1___=value1___:", t.GetPrefix()); -} -} // namespace diff --git a/spectator/util.h b/spectator/util.h deleted file mode 100644 index f971c31..0000000 --- a/spectator/util.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -namespace spectator { - -template -T restrict(T amount, T min, T max) { - auto r = amount; - if (r > max) { - r = max; - } else if (r < min) { - r = min; - } - return r; -} - -} // namespace spectator diff --git a/tools/gen_valid_chars.cc b/tools/gen_valid_chars.cc deleted file mode 100644 index ab046f0..0000000 --- a/tools/gen_valid_chars.cc +++ /dev/null @@ -1,48 +0,0 @@ -// generate the atlas valid charsets - -#include -#include - -void dump_array(std::ostream& os, const std::string& name, const std::array& chars) { - os << "static constexpr std::array " << name << " = {{"; - - os << chars[0]; - for (auto i = 1u; i < chars.size(); ++i) { - os << ", " << chars[i]; - } - - os << "}};\n"; -} - -int main(int argc, char* argv[]) { - std::ofstream of; - if (argc > 1) { - of.open(argv[1]); - } else { - of.open("/dev/stdout"); - } - - // default false - std::array charsAllowed{}; - for (int i = 0; i < 256; ++i) { - charsAllowed[i] = false; - } - - // configure allowed characters - charsAllowed['.'] = true; - charsAllowed['-'] = true; - - for (auto ch = '0'; ch <= '9'; ++ch) { - charsAllowed[ch] = true; - } - for (auto ch = 'a'; ch <= 'z'; ++ch) { - charsAllowed[ch] = true; - } - for (auto ch = 'A'; ch <= 'Z'; ++ch) { - charsAllowed[ch] = true; - } - charsAllowed['~'] = true; - charsAllowed['^'] = true; - - dump_array(of, "kAtlasChars", charsAllowed); -} From 1708a7613cfe76409b3c7eabe019b45e57a56615 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Wed, 11 Jun 2025 12:54:38 -0500 Subject: [PATCH 02/34] save work --- libs/config/README.md | 68 +++----- libs/config/include/config.h | 31 ++-- libs/config/src/config.cpp | 12 +- libs/config/test/test_config.cpp | 152 +++++++++--------- .../writer_config/include/writer_config.h | 3 +- .../writer_config/src/writer_config.cpp | 29 ++-- .../writer_config/test/test_writer_config.cpp | 101 ++++-------- .../writer_types/include/writer_types.h | 13 +- 8 files changed, 179 insertions(+), 230 deletions(-) diff --git a/libs/config/README.md b/libs/config/README.md index db69325..5056e7f 100644 --- a/libs/config/README.md +++ b/libs/config/README.md @@ -2,68 +2,40 @@ ## Overview -The `Config` class serves as the configuration object for the Registry class, which manages metrics for the spectatorD system. It defines how and where metrics are written and what additional tags are applied to them. +The `Config` class serves as the configuration object for the Registry class, which manages how metrics are sent to SpectatorD. +The `Config` constructor takes two parameters. The first parameter is required and is a `WriterConfig` object. This object defines +how metrics will be sent to `SpectatorD`. The second parameter `extraTags` is a unordered map of strings allowing you to provide additional tags to +all of your metrics. Extra tags are additional key-value pairs attached to all metrics and will be merged with environment-derived tags. ## Usage The `Config` class provides two constructors: ```cpp -// Constructor 1: Specify output location as string -Config(const std::string &location = "udp", - const std::unordered_map &extra_tags = {}); +// Constructor 1: Output location only -// Constructor 2: Specify writer type directly (recommended) -Config(WriterType type, - const std::unordered_map &extra_tags = {}); +// Example 1 +Config config(WriterConfig(WriterTypes::Memory)); +Config config(WriterConfig(WriterTypes::UDP)) -// Examples: +// Example 2 +const std::string udpUrl = std::string(WriterTypes::UDPURL) + "192.168.1.100:8125"; +Config config(WriterConfig(udpUrl)); -// Example 1: Create a default config (UDP output) -auto defaultConfig = Config(); +// Constructor 2: Output location and tags -// Example 2: Config with memory storage and custom tags -auto memoryConfig = Config("memory", { - {"app", "myService"}, - {"zone", "us-west-2"} -}); - -// Example 3: Config with direct writer type -auto stdoutConfig = Config(WriterTypes::Memory, { - {"env", "production"} -}); - -// Example 4: Config writing to a specific file -auto fileConfig = Config("file:///var/log/metrics.log"); - -// Example 5: Config sending to specific UDP endpoint -auto customUdpConfig = Config("udp://metrics-collector.example.com:8125"); +// Example 1 +std::unordered_map tags = {{"app", "test-app"}, {"env", "testing"}, {"region", "us-east-1"}}; +Config config(WriterConfig(WriterTypes::Memory), tags); ``` -### When to Use Each Constructor - -- Use the first constructor when you need to specify a custom output location. -- Use the second constructor (preferred) when working with standard writer types. - -### Output Locations - -Valid output locations include: -- `none`: Disable output -- `memory`: Store metrics in memory -- `stdout`: Write to standard output -- `stderr`: Write to standard error -- `udp`: Send metrics over UDP (default) -- `unix`: Use Unix domain sockets -- `file://path`: Write to a file -- `udp://host:port`: Send to specific UDP endpoint -- `unix://path`: Use specific Unix socket - -### Environment Variables +## Environment Variables -- `SPECTATOR_OUTPUT_LOCATION`: Override the configured output location +If the following environment variables are set and not empty, there key and value will also be read and applied to your tags - `TITUS_CONTAINER_NAME`: Set the `nf.container` tag automatically - `TITUS_PROCESS_NAME`: Set the `nf.process` tag automatically -## Extra Tags +### Warning -Extra tags are additional key-value pairs attached to all metrics. They can be specified during initialization and will be merged with environment-derived tags. \ No newline at end of file +If the environment variable `SPECTATOR_OUTPUT_LOCATION` is set this will override the value specefied in the `WriterConfig` +read the `WriterConfig` readme.md for more details. \ No newline at end of file diff --git a/libs/config/include/config.h b/libs/config/include/config.h index 27c5a61..d40f64b 100644 --- a/libs/config/include/config.h +++ b/libs/config/include/config.h @@ -7,26 +7,23 @@ class Config { - public: +public: + Config(const WriterConfig &writerConfig, const std::unordered_map &extraTags = {}); - Config(WriterConfig writerConfig, const std::unordered_map &extra_tags = {}); + ~Config() = default; + Config(const Config &other) = default; + Config &operator=(const Config &other) = delete; + Config(Config &&other) noexcept = delete; + Config &operator=(Config &&other) noexcept = delete; - // Rule of 5 - ~Config() = default; // Destructor - Config(const Config &other) = default; // Copy constructor - Config &operator=(const Config &other) = delete; // Copy assignment operator - Config(Config &&other) noexcept = delete; // Move constructor - Config &operator=(Config &&other) noexcept = delete; // Move assignment operator + const std::unordered_map &GetExtraTags() const noexcept { return m_extraTags; } - const std::string &GetLocation() const { return m_writerConfig.GetLocation(); } + const std::string &GetWriterLocation() const noexcept { return m_writerConfig.GetLocation(); } + const WriterType &GetWriterType() const noexcept { return m_writerConfig.GetType(); } - const std::unordered_map &GetExtraTags() const{ return m_extraTags;} +private: + std::unordered_map CalculateTags(const std::unordered_map &tags); - const WriterType &GetWriterType() const { return m_writerConfig.GetType();} - - private: - std::unordered_map CalculateTags(const std::unordered_map &tags); - - std::unordered_map m_extraTags; - WriterConfig m_writerConfig; + std::unordered_map m_extraTags; + WriterConfig m_writerConfig; }; \ No newline at end of file diff --git a/libs/config/src/config.cpp b/libs/config/src/config.cpp index 964562f..4b63bfd 100644 --- a/libs/config/src/config.cpp +++ b/libs/config/src/config.cpp @@ -8,8 +8,8 @@ struct ConfigConstants static constexpr auto envVarProcess = "TITUS_PROCESS_NAME"; }; -Config::Config(WriterConfig writerConfig, const std::unordered_map &extra_tags) - : m_extraTags(CalculateTags(extra_tags)), m_writerConfig(writerConfig) {} +Config::Config(const WriterConfig &writerConfig, const std::unordered_map &extraTags) + : m_extraTags(CalculateTags(extraTags)), m_writerConfig(writerConfig) {} std::unordered_map Config::CalculateTags(const std::unordered_map &tags) { @@ -17,19 +17,19 @@ std::unordered_map Config::CalculateTags(const std::un const char *container_name = std::getenv(ConfigConstants::envVarContainer); const char *process_name = std::getenv(ConfigConstants::envVarProcess); - if (container_name) + if (container_name != nullptr) { valid_tags[ConfigConstants::container] = container_name; } - - if (process_name) + + if (process_name != nullptr) { valid_tags[ConfigConstants::process] = process_name; } for (const auto &kv : tags) { - if (!kv.first.empty() && !kv.second.empty()) + if (kv.first.empty() == false && kv.second.empty() == false) { valid_tags[kv.first] = kv.second; } diff --git a/libs/config/test/test_config.cpp b/libs/config/test/test_config.cpp index 2f1f221..0311d3d 100644 --- a/libs/config/test/test_config.cpp +++ b/libs/config/test/test_config.cpp @@ -2,79 +2,56 @@ #include #include +#include -// Helper to temporarily set an environment variable for testing -class EnvVarSetter -{ - public: - EnvVarSetter(const std::string &name, const std::string &value) : m_name(name) +// Enhanced helper to temporarily modify an environment variable for testing +class EnvironmentVariableGuard { +public: + + EnvironmentVariableGuard(const std::string& name) : m_name(name) { - // Store original value (might be nullptr) - m_originalValue = std::getenv(name.c_str()); - - // Set the new value - setenv(name.c_str(), value.c_str(), 1); + if (const char* value = std::getenv(name.c_str())) + { + m_originalValue = value; + } } - ~EnvVarSetter() - { - // Restore original state - if (m_originalValue) - setenv(m_name.c_str(), m_originalValue, 1); - else - unsetenv(m_name.c_str()); - } - - private: - std::string m_name; - const char *m_originalValue; -}; - -// Helper to temporarily unset an environment variable -class EnvVarUnset -{ - public: - EnvVarUnset(const std::string &name) : m_name(name) - { - // Store original value (might be nullptr) - m_originalValue = std::getenv(name.c_str()); + void setValue(const std::string& value) { setenv(m_name.c_str(), value.c_str(), 1); } - // Always unset regardless of whether it was set before - unsetenv(name.c_str()); - } + void unsetValue() { unsetenv(m_name.c_str()); } - ~EnvVarUnset() + ~EnvironmentVariableGuard() { - // Only restore if there was an original value - if (m_originalValue) - setenv(m_name.c_str(), m_originalValue, 1); + if (m_originalValue.has_value()) { setenv(m_name.c_str(), m_originalValue->c_str(), 1); } + else { unsetenv(m_name.c_str()); } } - private: +private: std::string m_name; - const char *m_originalValue; + std::optional m_originalValue; }; -class ConfigTest : public ::testing::Test -{ - protected: - void SetUp() override - { +class ConfigTest : public ::testing::Test { +protected: + // Create guards for each environment variable + EnvironmentVariableGuard containerGuard{"TITUS_CONTAINER_NAME"}; + EnvironmentVariableGuard processGuard{"TITUS_PROCESS_NAME"}; + + void SetUp() override { // Ensure environment variables are unset before each test - unsetenv("TITUS_CONTAINER_NAME"); - unsetenv("TITUS_PROCESS_NAME"); + containerGuard.unsetValue(); + processGuard.unsetValue(); } }; // Test initialization with different writer configs -TEST_F(ConfigTest, WriterConfigInitialization) -{ +TEST_F(ConfigTest, WriterConfigInitialization) { // Test with memory writer { WriterConfig writerConfig(WriterTypes::Memory); Config config(writerConfig); - EXPECT_EQ(config.GetLocation(), ""); + EXPECT_EQ(config.GetWriterLocation(), ""); EXPECT_EQ(config.GetWriterType(), WriterType::Memory); EXPECT_TRUE(config.GetExtraTags().empty()); } @@ -84,14 +61,23 @@ TEST_F(ConfigTest, WriterConfigInitialization) WriterConfig writerConfig(WriterTypes::UDP); Config config(writerConfig); - EXPECT_EQ(config.GetLocation(), DefaultLocations::UDP); + EXPECT_EQ(config.GetWriterLocation(), DefaultLocations::UDP); EXPECT_EQ(config.GetWriterType(), WriterType::UDP); } + + // Test UDP URL + { + const std::string udpUrl = std::string(WriterTypes::UDPURL) + "192.168.1.100:8125"; + WriterConfig writerConfig(udpUrl); + Config config(writerConfig); + + EXPECT_EQ(config.GetWriterType(), WriterType::UDP); + EXPECT_EQ(config.GetWriterLocation(), udpUrl); + } } // Test extra tags handling -TEST_F(ConfigTest, ExtraTags) -{ +TEST_F(ConfigTest, ExtraTags) { WriterConfig writerConfig(WriterTypes::Memory); // Empty tags @@ -102,7 +88,12 @@ TEST_F(ConfigTest, ExtraTags) // Valid tags { - std::unordered_map tags = {{"app", "test-app"}, {"env", "testing"}, {"region", "us-east-1"}}; + std::unordered_map tags = + { + {"app", "test-app"}, + {"env", "testing"}, + {"region", "us-east-1"} + }; Config config(writerConfig, tags); @@ -114,7 +105,12 @@ TEST_F(ConfigTest, ExtraTags) // Invalid tags (empty keys or values should be ignored) { - std::unordered_map tags = {{"valid", "value"}, {"", "empty-key"}, {"empty-value", ""}}; + std::unordered_map tags = + { + {"valid", "value"}, + {"", "empty-key"}, + {"empty-value", ""} + }; Config config(writerConfig, tags); @@ -126,24 +122,20 @@ TEST_F(ConfigTest, ExtraTags) } // Test environment variable integration -TEST_F(ConfigTest, EnvironmentVariables) -{ +TEST_F(ConfigTest, EnvironmentVariables) { WriterConfig writerConfig(WriterTypes::Memory); - // No environment variables + // No environment variables - already unset in SetUp() { - EnvVarUnset container("TITUS_CONTAINER_NAME"); - EnvVarUnset process("TITUS_PROCESS_NAME"); - Config config(writerConfig); EXPECT_TRUE(config.GetExtraTags().empty()); } // With container name { - EnvVarSetter container("TITUS_CONTAINER_NAME", "test-container"); - EnvVarUnset process("TITUS_PROCESS_NAME"); - + containerGuard.setValue("test-container"); + // Process already unset from SetUp() + Config config(writerConfig); EXPECT_EQ(config.GetExtraTags().size(), 1); @@ -152,8 +144,8 @@ TEST_F(ConfigTest, EnvironmentVariables) // With process name { - EnvVarUnset container("TITUS_CONTAINER_NAME"); - EnvVarSetter process("TITUS_PROCESS_NAME", "test-process"); + containerGuard.unsetValue(); + processGuard.setValue("test-process"); Config config(writerConfig); @@ -163,8 +155,8 @@ TEST_F(ConfigTest, EnvironmentVariables) // With both environment variables { - EnvVarSetter container("TITUS_CONTAINER_NAME", "test-container"); - EnvVarSetter process("TITUS_PROCESS_NAME", "test-process"); + containerGuard.setValue("test-container"); + processGuard.setValue("test-process"); Config config(writerConfig); @@ -175,16 +167,19 @@ TEST_F(ConfigTest, EnvironmentVariables) } // Test merging of environment variables and explicit tags -TEST_F(ConfigTest, MergingTags) -{ +TEST_F(ConfigTest, MergingTags) { WriterConfig writerConfig(WriterTypes::Memory); // Environment variables with additional tags { - EnvVarSetter container("TITUS_CONTAINER_NAME", "test-container"); - EnvVarSetter process("TITUS_PROCESS_NAME", "test-process"); + containerGuard.setValue("test-container"); + processGuard.setValue("test-process"); - std::unordered_map tags = {{"custom", "value"}, {"env", "test"}}; + std::unordered_map tags = + { + {"custom", "value"}, + {"env", "test"} + }; Config config(writerConfig, tags); @@ -197,13 +192,16 @@ TEST_F(ConfigTest, MergingTags) // Override environment variables with explicit tags { - EnvVarSetter container("TITUS_CONTAINER_NAME", "test-container"); + containerGuard.setValue("test-container"); + processGuard.unsetValue(); - std::unordered_map tags = {{"nf.container", "override-container"}}; + std::unordered_map tags = { + {"nf.container", "override-container"} + }; Config config(writerConfig, tags); EXPECT_EQ(config.GetExtraTags().size(), 1); EXPECT_EQ(config.GetExtraTags().at("nf.container"), "override-container"); } -} +} \ No newline at end of file diff --git a/libs/writer/writer_config/include/writer_config.h b/libs/writer/writer_config/include/writer_config.h index 01059d7..ad372f6 100644 --- a/libs/writer/writer_config/include/writer_config.h +++ b/libs/writer/writer_config/include/writer_config.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -8,7 +9,7 @@ class WriterConfig { public: - WriterConfig(std::string type); + WriterConfig(const std::string &type); const WriterType &GetType() const noexcept { return m_type; }; diff --git a/libs/writer/writer_config/src/writer_config.cpp b/libs/writer/writer_config/src/writer_config.cpp index 6c288a4..13e5c14 100644 --- a/libs/writer/writer_config/src/writer_config.cpp +++ b/libs/writer/writer_config/src/writer_config.cpp @@ -1,5 +1,10 @@ #include +struct WriterConfigConstants +{ + static constexpr auto RuntimeErrorMessage = "Invalid writer type: "; +}; + std::pair GetWriterConfigFromString(const std::string &type) { // Check exact matches first @@ -9,29 +14,27 @@ std::pair GetWriterConfigFromString(const std::string & return {it->second.first, std::string(it->second.second)}; } - else if (type.rfind(WriterTypes::UDPURL, 0) == 0) + if (type.rfind(WriterTypes::UDPURL, 0) == 0) { return {WriterType::UDP, type}; } - else if (type.rfind(WriterTypes::UnixURL, 0) == 0) + + if (type.rfind(WriterTypes::UnixURL, 0) == 0) { return {WriterType::Unix, type}; } - throw std::invalid_argument("Invalid writer type: " + type); + throw std::runtime_error(WriterConfigConstants::RuntimeErrorMessage + type); } - - -WriterConfig::WriterConfig(std::string type) +WriterConfig::WriterConfig(const std::string &type) { const char *envLocation = std::getenv("SPECTATOR_OUTPUT_LOCATION"); - try { if (envLocation != nullptr) { - // If environment variable is set, use it instead of the constructor parameter + Logger::debug("Using environment variable SPECTATOR_OUTPUT_LOCATION: {}", envLocation); std::string envValue(envLocation); auto [writer_type, location] = GetWriterConfigFromString(envValue); m_type = writer_type; @@ -39,14 +42,18 @@ WriterConfig::WriterConfig(std::string type) } else { - // If no environment variable, use the type passed to the constructor + Logger::debug("Using provided type: {}", type); auto [writer_type, location] = GetWriterConfigFromString(type); m_type = writer_type; m_location = location; } + Logger::debug("WriterConfig initialized with type: {}, location: {}", WriterTypeToString(m_type), m_location); } - catch (const std::invalid_argument &e) + catch (const std::exception& e) { - throw std::invalid_argument("Invalid writer type: " + (envLocation != nullptr ? std::string(envLocation) : type)); + // TODO: Throwing same exception twice + // Matthew: Catch exception and default to udp or exit? + Logger::error("Failed to initialize WriterConfig: {}", e.what()); + throw std::runtime_error(WriterConfigConstants::RuntimeErrorMessage + type); } } \ No newline at end of file diff --git a/libs/writer/writer_config/test/test_writer_config.cpp b/libs/writer/writer_config/test/test_writer_config.cpp index 2056290..fd8ee66 100644 --- a/libs/writer/writer_config/test/test_writer_config.cpp +++ b/libs/writer/writer_config/test/test_writer_config.cpp @@ -4,75 +4,52 @@ #include #include +#include -// Helper to temporarily set an environment variable for testing -class EnvironmentVariableSetter +// Enhanced helper to temporarily modify an environment variable for testing +class EnvironmentVariableGuard { - public: - EnvironmentVariableSetter(const std::string &name, const std::string &value) : m_name(name) - { - // Store original value (might be nullptr) - m_originalValue = std::getenv(name.c_str()); - - // Set the new value - setenv(name.c_str(), value.c_str(), 1); - } +public: - ~EnvironmentVariableSetter() + EnvironmentVariableGuard(const std::string& name) : m_name(name) { - // Restore original state - if (m_originalValue) - setenv(m_name.c_str(), m_originalValue, 1); - else - unsetenv(m_name.c_str()); + if (const char* value = std::getenv(name.c_str())) + { + m_originalValue = value; + } } - private: - std::string m_name; - const char *m_originalValue; -}; - -// Helper to temporarily unset an environment variable for testing -class EnvironmentVariableUnset -{ - public: - EnvironmentVariableUnset(const std::string &name) : m_name(name) + void setValue(const std::string& value) { - // Store original value (might be nullptr) - m_originalValue = std::getenv(name.c_str()); - - // Always unset regardless of whether it was set before - unsetenv(name.c_str()); + setenv(m_name.c_str(), value.c_str(), 1); } - ~EnvironmentVariableUnset() + void unsetValue() { unsetenv(m_name.c_str()); } + + ~EnvironmentVariableGuard() { - // Only restore if there was an original value - if (m_originalValue) - setenv(m_name.c_str(), m_originalValue, 1); + if (m_originalValue.has_value()) { setenv(m_name.c_str(), m_originalValue->c_str(), 1); } + else { unsetenv(m_name.c_str()); } } - private: +private: std::string m_name; - const char *m_originalValue; + std::optional m_originalValue; }; -// Test fixture for WriterConfig tests -class WriterConfigTest : public ::testing::Test -{ - protected: - void SetUp() override +class WriterConfigTest : public ::testing::Test { +protected: + EnvironmentVariableGuard envGuard{"SPECTATOR_OUTPUT_LOCATION"}; + + void SetUp() override { - // Ensure environment variable is unset before each test - unsetenv("SPECTATOR_OUTPUT_LOCATION"); + envGuard.unsetValue(); } }; -// Test basic writer type initialization + TEST_F(WriterConfigTest, BasicWriterTypes) { - - // Test "memory" type { WriterConfig config(WriterTypes::Memory); @@ -95,10 +72,9 @@ TEST_F(WriterConfigTest, BasicWriterTypes) } } -// Test URL-based writer initialization + TEST_F(WriterConfigTest, URLBasedWriterTypes) { - // Test UDP URL { const std::string udpUrl = std::string(WriterTypes::UDPURL) + "192.168.1.100:8125"; @@ -116,49 +92,36 @@ TEST_F(WriterConfigTest, URLBasedWriterTypes) } } -// Test environment variable override TEST_F(WriterConfigTest, EnvironmentVariableOverride) { - // Test environment variable overriding constructor parameter { - EnvironmentVariableSetter setter("SPECTATOR_OUTPUT_LOCATION", WriterTypes::Memory); + envGuard.setValue(WriterTypes::Memory); WriterConfig config(WriterTypes::UDP); // This should be ignored due to env var EXPECT_EQ(config.GetType(), WriterType::Memory); EXPECT_EQ(config.GetLocation(), DefaultLocations::NoLocation); } - - // Test with environment variable unset { - EnvironmentVariableUnset unset("SPECTATOR_OUTPUT_LOCATION"); + envGuard.unsetValue(); WriterConfig config(WriterTypes::Memory); EXPECT_EQ(config.GetType(), WriterType::Memory); EXPECT_EQ(config.GetLocation(), DefaultLocations::NoLocation); } } -// Test invalid writer type handling TEST_F(WriterConfigTest, InvalidWriterType) { - // Test invalid type from constructor - EXPECT_THROW({ WriterConfig config("invalid_type"); }, std::invalid_argument); + EXPECT_THROW({ WriterConfig config("invalid_type"); }, std::runtime_error); + EXPECT_THROW({ WriterConfig config(""); }, std::runtime_error); - // Test invalid type from environment variable { - EnvironmentVariableSetter setter("SPECTATOR_OUTPUT_LOCATION", "invalid_env_value"); - EXPECT_THROW( - { - WriterConfig config("none"); // This should be ignored, env var used instead - }, - std::invalid_argument); + envGuard.setValue("invalid_env_value"); + EXPECT_THROW({WriterConfig config(WriterTypes::Memory);}, std::runtime_error); } } -// Test case for edge cases TEST_F(WriterConfigTest, EdgeCases) { - // Test empty string - EXPECT_THROW({ WriterConfig config(""); }, std::invalid_argument); // Test with just URL scheme but no path { diff --git a/libs/writer/writer_types/include/writer_types.h b/libs/writer/writer_types/include/writer_types.h index 0409d0e..96a05c6 100644 --- a/libs/writer/writer_types/include/writer_types.h +++ b/libs/writer/writer_types/include/writer_types.h @@ -40,4 +40,15 @@ inline const std::map> {WriterTypes::Memory, {WriterType::Memory, DefaultLocations::NoLocation}}, {WriterTypes::UDP, {WriterType::UDP, DefaultLocations::UDP}}, {WriterTypes::Unix, {WriterType::Unix, DefaultLocations::UDS}}, -}; \ No newline at end of file +}; + +inline std::string WriterTypeToString(WriterType type) +{ + switch (type) + { + case WriterType::Memory: return WriterTypes::Memory; + case WriterType::UDP: return WriterTypes::UDP; + case WriterType::Unix: return WriterTypes::Unix; + default: return "Unknown"; + } +} \ No newline at end of file From 369d13d54cfaa436c3101818868768de5046f272 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Wed, 11 Jun 2025 13:00:58 -0500 Subject: [PATCH 03/34] save work --- libs/writer/README.md | 89 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 libs/writer/README.md diff --git a/libs/writer/README.md b/libs/writer/README.md new file mode 100644 index 0000000..fd20412 --- /dev/null +++ b/libs/writer/README.md @@ -0,0 +1,89 @@ +# Writer Module + +The Writer module provides a flexible system for metric data output in the Spectator C++ library. It consists of several components that handle different aspects of data writing. + +## Components + +### Writer Types (`writer_types`) + +This component defines the available writer types and their associated configurations: + +- **Supported Writer Types:** + - `Memory` - Writes data to an in-memory buffer (primarily for testing) + - `UDP` - Writes data over UDP to a specified endpoint + - `Unix` - Writes data to a Unix Domain Socket + +- **Key Features:** + - Type enumeration via `WriterType` enum class + - String constants for type names in `WriterTypes` struct + - Default locations for different writer types in `DefaultLocations` struct + - Type-to-location mapping in `TypeToLocationMap` + - String conversion via `WriterTypeToString()` function + +### Writer Config (`writer_config`) + +This component handles configuration of writers: + +- **Key Features:** + - Parses writer configuration from string identifiers + - Handles environment variable overrides via `SPECTATOR_OUTPUT_LOCATION` + - Error handling for invalid writer types + - Provides a clean API for specifying writer type and location + +- **Usage Example:** + ```cpp + // Create a writer config with a specific type + WriterConfig config(WriterTypes::UDP); + + // Or with a URL-style location + WriterConfig config("udp://192.168.1.100:8125"); + + // Environment variable overrides any provided value + // SPECTATOR_OUTPUT_LOCATION=unix:///custom/path/socket.sock + WriterConfig config(WriterTypes::UDP); // Will use Unix socket instead + ``` + +### Writer Wrapper (`writer_wrapper`) + +This component provides a wrapper around the different writer implementations: + +- **Key Features:** + - Common interface for all writer types + - Factory pattern for creating writers based on configuration + - Handles serialization and transmission of metric data + - Abstracts transport details from the rest of the library + +## Integration + +These components work together to provide a flexible metric output system: + +1. `writer_types` defines the available writer types and their default configurations +2. `writer_config` handles parsing and validating configuration values +3. `writer_wrapper` instantiates the appropriate writer implementation + +## Best Practices + +- Use the environment variable `SPECTATOR_OUTPUT_LOCATION` for runtime configuration +- Prefer URL-style configurations for explicit endpoint specification +- For UDP: `udp://host:port` +- For Unix Domain Sockets: `unix:///path/to/socket` + +## Example + +```cpp +// Create a configuration +WriterConfig writerConfig("udp://localhost:8125"); + +// Create a configuration object with the writer config +Config config(writerConfig); + +// Additional tags can be added +std::unordered_map tags = { + {"app", "my-application"}, + {"env", "production"} +}; +Config config(writerConfig, tags); + +// The config can be used to create a registry +auto registry = spectator::Registry(config); +``` \ No newline at end of file From a6591adfd0efc91162839d3d996c892b21ca9d98 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Wed, 11 Jun 2025 13:33:03 -0500 Subject: [PATCH 04/34] clean up meter --- libs/meter/meter_id/include/meter_id.h | 20 ++------- libs/meter/meter_id/src/meter_id.cpp | 43 +++++++++++-------- libs/meter/meter_types/include/age_gauge.h | 4 +- libs/meter/meter_types/include/counter.h | 2 +- libs/meter/meter_types/include/dist_summary.h | 2 +- libs/meter/meter_types/include/gauge.h | 2 +- libs/meter/meter_types/include/max_gauge.h | 2 +- .../meter_types/include/monotonic_counter.h | 2 +- .../include/monotonic_counter_uint.h | 2 +- .../include/percentile_dist_summary.h | 2 +- .../meter_types/include/percentile_timer.h | 2 +- libs/meter/meter_types/include/timer.h | 2 +- .../writer_config/src/writer_config.cpp | 34 ++++++--------- 13 files changed, 51 insertions(+), 68 deletions(-) diff --git a/libs/meter/meter_id/include/meter_id.h b/libs/meter/meter_id/include/meter_id.h index c8f4fbf..18a895f 100644 --- a/libs/meter/meter_id/include/meter_id.h +++ b/libs/meter/meter_id/include/meter_id.h @@ -12,37 +12,25 @@ class MeterId MeterId(const std::string &name, const std::unordered_map &tags = {}); const std::string &GetName() const noexcept { return m_name; }; - + const std::string &GetSpectatordId() const noexcept { return m_spectatord_id; } const std::unordered_map &GetTags() const noexcept { return m_tags; }; MeterId WithTag(const std::string &key, const std::string &value) const; MeterId WithTags(const std::unordered_map &additional_tags) const; - std::string spectatord_id; - bool operator==(const MeterId &other) const; std::string to_string() const; - std::string GetSpectatordId() const - { - return ToSpectatorId(m_name, m_tags); - } - private: - std::string RepleaceInvalidChars(const std::string &s) const; - std::string ToSpectatorId(const std::string &name, const std::unordered_map &tags) const; - - static const std::regex INVALID_CHARS; std::string m_name; std::unordered_map m_tags; + std::string m_spectatord_id; }; -namespace std -{ -template <> struct hash + +template <> struct std::hash { size_t operator()(const MeterId &id) const; }; -} // namespace std \ No newline at end of file diff --git a/libs/meter/meter_id/src/meter_id.cpp b/libs/meter/meter_id/src/meter_id.cpp index cfec332..6fd623c 100644 --- a/libs/meter/meter_id/src/meter_id.cpp +++ b/libs/meter/meter_id/src/meter_id.cpp @@ -4,7 +4,7 @@ #include // Define the static member -const std::regex MeterId::INVALID_CHARS("[^-._A-Za-z0-9~^]"); +const std::regex INVALID_CHARS("[^-._A-Za-z0-9~^]"); std::unordered_map ValidateTags(const std::unordered_map &tags) { @@ -21,10 +21,32 @@ std::unordered_map ValidateTags(const std::unordered_m return validTags; } +std::string RepleaceInvalidChars(const std::string &s) +{ + return std::regex_replace(s, INVALID_CHARS, "_"); +} + +std::string ToSpectatorId(const std::string &name, const std::unordered_map &tags) +{ + std::ostringstream ss; + ss << RepleaceInvalidChars(name); + if (!tags.empty()) + { + for (const auto &tag : tags) + { + ss << "," << RepleaceInvalidChars(tag.first) << "=" << RepleaceInvalidChars(tag.second); + } + } + return ss.str(); +} + + + + MeterId::MeterId(const std::string &name, const std::unordered_map &tags) : m_name(name), m_tags(ValidateTags(tags)) { - spectatord_id = ToSpectatorId(m_name, m_tags); + m_spectatord_id = ToSpectatorId(name, tags); } MeterId MeterId::WithTag(const std::string &key, const std::string &value) const @@ -67,24 +89,7 @@ std::string MeterId::to_string() const return ss.str(); } -std::string MeterId::RepleaceInvalidChars(const std::string &s) const -{ - return std::regex_replace(s, INVALID_CHARS, "_"); -} -std::string MeterId::ToSpectatorId(const std::string &name, const std::unordered_map &tags) const -{ - std::ostringstream ss; - ss << RepleaceInvalidChars(name); - if (!tags.empty()) - { - for (const auto &tag : tags) - { - ss << "," << RepleaceInvalidChars(tag.first) << "=" << RepleaceInvalidChars(tag.second); - } - } - return ss.str(); -} // Implementation of the hash function for MeterId size_t std::hash::operator()(const MeterId &id) const diff --git a/libs/meter/meter_types/include/age_gauge.h b/libs/meter/meter_types/include/age_gauge.h index fc478ae..230443a 100644 --- a/libs/meter/meter_types/include/age_gauge.h +++ b/libs/meter/meter_types/include/age_gauge.h @@ -17,13 +17,13 @@ class AgeGauge final : public Meter void Now() { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + "0"; + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + "0"; Writer::GetInstance().Write(line); } void Set(const int &seconds) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(seconds); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(seconds); Writer::GetInstance().Write(line); } }; diff --git a/libs/meter/meter_types/include/counter.h b/libs/meter/meter_types/include/counter.h index cec6209..8860fcc 100644 --- a/libs/meter/meter_types/include/counter.h +++ b/libs/meter/meter_types/include/counter.h @@ -19,7 +19,7 @@ class Counter final : public Meter { if (delta > 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(delta); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(delta); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/dist_summary.h b/libs/meter/meter_types/include/dist_summary.h index 05fd5a2..a965e46 100644 --- a/libs/meter/meter_types/include/dist_summary.h +++ b/libs/meter/meter_types/include/dist_summary.h @@ -19,7 +19,7 @@ class DistributionSummary final : public Meter { if (amount >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(amount); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(amount); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/gauge.h b/libs/meter/meter_types/include/gauge.h index d29a96c..59ec1d3 100644 --- a/libs/meter/meter_types/include/gauge.h +++ b/libs/meter/meter_types/include/gauge.h @@ -20,7 +20,7 @@ class Gauge final : public Meter void Set(const double &value) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(value); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(value); Writer::GetInstance().Write(line); } }; \ No newline at end of file diff --git a/libs/meter/meter_types/include/max_gauge.h b/libs/meter/meter_types/include/max_gauge.h index 5d84319..e6700d7 100644 --- a/libs/meter/meter_types/include/max_gauge.h +++ b/libs/meter/meter_types/include/max_gauge.h @@ -17,7 +17,7 @@ class MaxGauge final : public Meter void Set(const double &value) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(value); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(value); Writer::GetInstance().Write(line); } }; \ No newline at end of file diff --git a/libs/meter/meter_types/include/monotonic_counter.h b/libs/meter/meter_types/include/monotonic_counter.h index 86a12a9..3c61b4a 100644 --- a/libs/meter/meter_types/include/monotonic_counter.h +++ b/libs/meter/meter_types/include/monotonic_counter.h @@ -17,7 +17,7 @@ class MonotonicCounter final : public Meter void Set(const double &amount) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(amount); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(amount); Writer::GetInstance().Write(line); } }; diff --git a/libs/meter/meter_types/include/monotonic_counter_uint.h b/libs/meter/meter_types/include/monotonic_counter_uint.h index 48b51cb..bd1b114 100644 --- a/libs/meter/meter_types/include/monotonic_counter_uint.h +++ b/libs/meter/meter_types/include/monotonic_counter_uint.h @@ -17,7 +17,7 @@ class MonotonicCounterUint final : public Meter void Set(const uint64_t &amount) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(amount); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(amount); Writer::GetInstance().Write(line); } }; diff --git a/libs/meter/meter_types/include/percentile_dist_summary.h b/libs/meter/meter_types/include/percentile_dist_summary.h index 10147ab..ca44cb4 100644 --- a/libs/meter/meter_types/include/percentile_dist_summary.h +++ b/libs/meter/meter_types/include/percentile_dist_summary.h @@ -20,7 +20,7 @@ class PercentileDistributionSummary final : public Meter { if (amount >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(amount); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(amount); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/percentile_timer.h b/libs/meter/meter_types/include/percentile_timer.h index 379f564..270b016 100644 --- a/libs/meter/meter_types/include/percentile_timer.h +++ b/libs/meter/meter_types/include/percentile_timer.h @@ -19,7 +19,7 @@ class PercentileTimer final : public Meter { if (seconds >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(seconds); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(seconds); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/timer.h b/libs/meter/meter_types/include/timer.h index 3ae106d..e787cc2 100644 --- a/libs/meter/meter_types/include/timer.h +++ b/libs/meter/meter_types/include/timer.h @@ -19,7 +19,7 @@ class Timer final : public Meter { if (seconds >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.spectatord_id + FIELD_SEPARATOR + std::to_string(seconds); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(seconds); Writer::GetInstance().Write(line); } } diff --git a/libs/writer/writer_config/src/writer_config.cpp b/libs/writer/writer_config/src/writer_config.cpp index 13e5c14..1cecec7 100644 --- a/libs/writer/writer_config/src/writer_config.cpp +++ b/libs/writer/writer_config/src/writer_config.cpp @@ -30,30 +30,20 @@ std::pair GetWriterConfigFromString(const std::string & WriterConfig::WriterConfig(const std::string &type) { const char *envLocation = std::getenv("SPECTATOR_OUTPUT_LOCATION"); - try + if (envLocation != nullptr) { - if (envLocation != nullptr) - { - Logger::debug("Using environment variable SPECTATOR_OUTPUT_LOCATION: {}", envLocation); - std::string envValue(envLocation); - auto [writer_type, location] = GetWriterConfigFromString(envValue); - m_type = writer_type; - m_location = location; - } - else - { - Logger::debug("Using provided type: {}", type); - auto [writer_type, location] = GetWriterConfigFromString(type); - m_type = writer_type; - m_location = location; - } - Logger::debug("WriterConfig initialized with type: {}, location: {}", WriterTypeToString(m_type), m_location); + Logger::debug("Using environment variable SPECTATOR_OUTPUT_LOCATION: {}", envLocation); + std::string envValue(envLocation); + auto [writer_type, location] = GetWriterConfigFromString(envValue); + m_type = writer_type; + m_location = location; } - catch (const std::exception& e) + else { - // TODO: Throwing same exception twice - // Matthew: Catch exception and default to udp or exit? - Logger::error("Failed to initialize WriterConfig: {}", e.what()); - throw std::runtime_error(WriterConfigConstants::RuntimeErrorMessage + type); + Logger::debug("Using provided type: {}", type); + auto [writer_type, location] = GetWriterConfigFromString(type); + m_type = writer_type; + m_location = location; } + Logger::debug("WriterConfig initialized with type: {}, location: {}", WriterTypeToString(m_type), m_location); } \ No newline at end of file From 051147bdba80dcfdbe79912ddf229c3ce713213b Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Wed, 11 Jun 2025 14:58:03 -0500 Subject: [PATCH 05/34] fix docker build --- Dockerfiles/README.md | 6 +++--- Dockerfiles/Ubuntu.Dockerfile | 3 ++- libs/config/CMakeLists.txt | 5 +++++ libs/meter/meter_id/src/meter_id.cpp | 3 --- libs/writer/writer_config/CMakeLists.txt | 1 + 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Dockerfiles/README.md b/Dockerfiles/README.md index 43e97c5..1adfc42 100644 --- a/Dockerfiles/README.md +++ b/Dockerfiles/README.md @@ -13,7 +13,7 @@ following commands from the root directory of the project. ```shell sudo docker build -t spectator-cpp-image -f Dockerfiles/Ubuntu.Dockerfile . -sudo docker run -it spectatord-cpp-image +sudo docker run -it spectator-cpp-image ./build.sh ``` @@ -24,8 +24,8 @@ sudo docker run -it spectatord-cpp-image - Start `Docker` before opening `Powershell` ```shell -docker build -t spectatord-cpp-image -f Dockerfiles/Ubuntu.Dockerfile . -docker run -it spectatord-cpp-image +docker build -t spectator-cpp-image -f Dockerfiles/Ubuntu.Dockerfile . +docker run -it spectator-cpp-image /bin/bash apt-get install dos2unix dos2unix build.sh ./build.sh diff --git a/Dockerfiles/Ubuntu.Dockerfile b/Dockerfiles/Ubuntu.Dockerfile index 8d957a9..97662a8 100644 --- a/Dockerfiles/Ubuntu.Dockerfile +++ b/Dockerfiles/Ubuntu.Dockerfile @@ -9,7 +9,8 @@ RUN apt-get update && apt-get install -y \ python3-venv \ gcc-13\ g++-13 \ - cmake + cmake \ + build-essential # Create a default working directory WORKDIR /home/ubuntu/spectator-cpp diff --git a/libs/config/CMakeLists.txt b/libs/config/CMakeLists.txt index 87d5bba..6c1682a 100644 --- a/libs/config/CMakeLists.txt +++ b/libs/config/CMakeLists.txt @@ -6,6 +6,11 @@ target_include_directories(spectator-config PUBLIC ${CMAKE_SOURCE_DIR} ) +target_link_libraries(spectator-config + PUBLIC + spectator-writer-config +) + add_executable(config-tests test/test_config.cpp ) diff --git a/libs/meter/meter_id/src/meter_id.cpp b/libs/meter/meter_id/src/meter_id.cpp index 6fd623c..61611ae 100644 --- a/libs/meter/meter_id/src/meter_id.cpp +++ b/libs/meter/meter_id/src/meter_id.cpp @@ -40,9 +40,6 @@ std::string ToSpectatorId(const std::string &name, const std::unordered_map &tags) : m_name(name), m_tags(ValidateTags(tags)) { diff --git a/libs/writer/writer_config/CMakeLists.txt b/libs/writer/writer_config/CMakeLists.txt index 58d1d53..8200620 100644 --- a/libs/writer/writer_config/CMakeLists.txt +++ b/libs/writer/writer_config/CMakeLists.txt @@ -12,6 +12,7 @@ target_include_directories(spectator-writer-config target_link_libraries(spectator-writer-config PUBLIC spectator-writer-types + spectator-logger ) add_executable(test_writer_config From 0c3a439302c7a1423c776d0454d49973ec164edb Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Sun, 15 Jun 2025 22:12:15 -0500 Subject: [PATCH 06/34] Reformat and add clang settings --- .clang-format | 86 ++++++++++++ README.md | 2 +- libs/config/include/config.h | 29 ++-- libs/config/src/config.cpp | 21 +-- libs/config/test/test_config.cpp | 74 +++++----- libs/logger/logger.h | 61 ++++---- libs/meter/meter_id/include/meter_id.h | 24 ++-- libs/meter/meter_id/src/meter_id.cpp | 35 ++--- libs/meter/meter_id/test/test_meter_id.cpp | 4 +- libs/meter/meter_types/include/age_gauge.h | 11 +- libs/meter/meter_types/include/base/meter.h | 17 +-- libs/meter/meter_types/include/counter.h | 11 +- libs/meter/meter_types/include/dist_summary.h | 11 +- libs/meter/meter_types/include/gauge.h | 14 +- libs/meter/meter_types/include/max_gauge.h | 11 +- .../meter_types/include/monotonic_counter.h | 11 +- .../include/monotonic_counter_uint.h | 11 +- .../include/percentile_dist_summary.h | 9 +- .../meter_types/include/percentile_timer.h | 11 +- libs/meter/meter_types/include/timer.h | 11 +- .../meter/meter_types/test/test_age_gauge.cpp | 6 +- libs/meter/meter_types/test/test_counter.cpp | 6 +- .../meter_types/test/test_dist_summary.cpp | 8 +- libs/meter/meter_types/test/test_gauge.cpp | 16 +-- .../meter/meter_types/test/test_max_gauge.cpp | 4 +- .../test/test_monotonic_counter.cpp | 6 +- .../test/test_monotonic_counter_uint.cpp | 6 +- .../test/test_percentile_dist_summary.cpp | 8 +- .../test/test_percentile_timer.cpp | 8 +- libs/meter/meter_types/test/test_timer.cpp | 8 +- libs/utils/include/singleton.h | 15 +- libs/utils/include/util.h | 6 +- libs/utils/src/util.cpp | 8 +- .../writer_config/include/writer_config.h | 14 +- .../writer_config/src/writer_config.cpp | 18 +-- .../writer_config/test/test_writer_config.cpp | 45 +++--- .../writer_types/include/base/base_writer.h | 16 +-- .../writer_types/include/memory_writer.h | 19 ++- libs/writer/writer_types/include/udp_writer.h | 8 +- libs/writer/writer_types/include/uds_writer.h | 8 +- .../writer_types/include/writer_types.h | 24 ++-- .../writer/writer_types/src/memory_writer.cpp | 4 +- libs/writer/writer_types/src/udp_writer.cpp | 16 +-- libs/writer/writer_types/src/uds_writer.cpp | 26 ++-- .../writer_types/test/test_memory_writer.cpp | 2 +- .../writer_types/test/test_udp_writer.cpp | 12 +- .../writer_types/test/test_uds_writer.cpp | 6 +- .../test_utils/udp_server/udp_server.cpp | 8 +- .../test_utils/udp_server/udp_server.h | 2 +- .../test_utils/uds_server/uds_server.cpp | 6 +- .../test_utils/uds_server/uds_server.h | 2 +- libs/writer/writer_wrapper/include/Writer.h | 35 ++--- .../include/writer_test_helper.h | 14 +- libs/writer/writer_wrapper/src/Writer.cpp | 53 ++++--- requirements.txt | 2 +- spectator/include/registry.h | 69 +++++----- spectator/src/registry.cpp | 73 ++++------ spectator/test/test_registry.cpp | 130 ++++++++++-------- 58 files changed, 607 insertions(+), 574 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..1bfe00b --- /dev/null +++ b/.clang-format @@ -0,0 +1,86 @@ +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: None +AlignConsecutiveDeclarations: None +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: Never +SpaceAfterCStyleCast: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 8 +UseTab: Never \ No newline at end of file diff --git a/README.md b/README.md index d5d3791..d80fe38 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ By default, the library sends every meter change to the spectatord sidecar immed `send` call and underlying system calls, and may not be the most efficient way to publish metrics in high-volume use cases. For this purpose a simple buffering functionality in `Publisher` is implemented, and it can be turned on by passing a buffer size to the `spectator::Config` constructor. It is important to note that, until this buffer -fills up, the `Publisher` will not send nay meters to the sidecar. Therefore, if your application doesn't emit +fills up, the `Publisher` will not send any meters to the sidecar. Therefore, if your application doesn't emit meters at a high rate, you should either keep the buffer very small, or do not configure a buffer size at all, which will fall back to the "publish immediately" mode of operation. diff --git a/libs/config/include/config.h b/libs/config/include/config.h index d40f64b..9b8cd4c 100644 --- a/libs/config/include/config.h +++ b/libs/config/include/config.h @@ -7,23 +7,24 @@ class Config { -public: - Config(const WriterConfig &writerConfig, const std::unordered_map &extraTags = {}); + public: + Config(const WriterConfig& writerConfig, const std::unordered_map& extraTags = {}); - ~Config() = default; - Config(const Config &other) = default; - Config &operator=(const Config &other) = delete; - Config(Config &&other) noexcept = delete; - Config &operator=(Config &&other) noexcept = delete; + ~Config() = default; + Config(const Config& other) = default; + Config& operator=(const Config& other) = delete; + Config(Config&& other) noexcept = delete; + Config& operator=(Config&& other) noexcept = delete; - const std::unordered_map &GetExtraTags() const noexcept { return m_extraTags; } + const std::unordered_map& GetExtraTags() const noexcept { return m_extraTags; } - const std::string &GetWriterLocation() const noexcept { return m_writerConfig.GetLocation(); } - const WriterType &GetWriterType() const noexcept { return m_writerConfig.GetType(); } + const std::string& GetWriterLocation() const noexcept { return m_writerConfig.GetLocation(); } + const WriterType& GetWriterType() const noexcept { return m_writerConfig.GetType(); } -private: - std::unordered_map CalculateTags(const std::unordered_map &tags); + private: + std::unordered_map CalculateTags( + const std::unordered_map& tags); - std::unordered_map m_extraTags; - WriterConfig m_writerConfig; + std::unordered_map m_extraTags; + WriterConfig m_writerConfig; }; \ No newline at end of file diff --git a/libs/config/src/config.cpp b/libs/config/src/config.cpp index 4b63bfd..db5ecbf 100644 --- a/libs/config/src/config.cpp +++ b/libs/config/src/config.cpp @@ -2,21 +2,24 @@ struct ConfigConstants { - static constexpr auto container = "nf.container"; - static constexpr auto process = "nf.process"; + static constexpr auto container = "nf.container"; + static constexpr auto process = "nf.process"; static constexpr auto envVarContainer = "TITUS_CONTAINER_NAME"; - static constexpr auto envVarProcess = "TITUS_PROCESS_NAME"; + static constexpr auto envVarProcess = "TITUS_PROCESS_NAME"; }; -Config::Config(const WriterConfig &writerConfig, const std::unordered_map &extraTags) - : m_extraTags(CalculateTags(extraTags)), m_writerConfig(writerConfig) {} +Config::Config(const WriterConfig& writerConfig, const std::unordered_map& extraTags) + : m_extraTags(CalculateTags(extraTags)), m_writerConfig(writerConfig) +{ +} -std::unordered_map Config::CalculateTags(const std::unordered_map &tags) +std::unordered_map Config::CalculateTags( + const std::unordered_map& tags) { std::unordered_map valid_tags; - const char *container_name = std::getenv(ConfigConstants::envVarContainer); - const char *process_name = std::getenv(ConfigConstants::envVarProcess); + const char* container_name = std::getenv(ConfigConstants::envVarContainer); + const char* process_name = std::getenv(ConfigConstants::envVarProcess); if (container_name != nullptr) { valid_tags[ConfigConstants::container] = container_name; @@ -27,7 +30,7 @@ std::unordered_map Config::CalculateTags(const std::un valid_tags[ConfigConstants::process] = process_name; } - for (const auto &kv : tags) + for (const auto& kv : tags) { if (kv.first.empty() == false && kv.second.empty() == false) { diff --git a/libs/config/test/test_config.cpp b/libs/config/test/test_config.cpp index 0311d3d..6f495f5 100644 --- a/libs/config/test/test_config.cpp +++ b/libs/config/test/test_config.cpp @@ -5,12 +5,12 @@ #include // Enhanced helper to temporarily modify an environment variable for testing -class EnvironmentVariableGuard { -public: - - EnvironmentVariableGuard(const std::string& name) : m_name(name) +class EnvironmentVariableGuard +{ + public: + EnvironmentVariableGuard(const std::string& name) : m_name(name) { - if (const char* value = std::getenv(name.c_str())) + if (const char* value = std::getenv(name.c_str())) { m_originalValue = value; } @@ -20,24 +20,32 @@ class EnvironmentVariableGuard { void unsetValue() { unsetenv(m_name.c_str()); } - ~EnvironmentVariableGuard() + ~EnvironmentVariableGuard() { - if (m_originalValue.has_value()) { setenv(m_name.c_str(), m_originalValue->c_str(), 1); } - else { unsetenv(m_name.c_str()); } + if (m_originalValue.has_value()) + { + setenv(m_name.c_str(), m_originalValue->c_str(), 1); + } + else + { + unsetenv(m_name.c_str()); + } } -private: + private: std::string m_name; std::optional m_originalValue; }; -class ConfigTest : public ::testing::Test { -protected: +class ConfigTest : public ::testing::Test +{ + protected: // Create guards for each environment variable EnvironmentVariableGuard containerGuard{"TITUS_CONTAINER_NAME"}; EnvironmentVariableGuard processGuard{"TITUS_PROCESS_NAME"}; - - void SetUp() override { + + void SetUp() override + { // Ensure environment variables are unset before each test containerGuard.unsetValue(); processGuard.unsetValue(); @@ -45,7 +53,8 @@ class ConfigTest : public ::testing::Test { }; // Test initialization with different writer configs -TEST_F(ConfigTest, WriterConfigInitialization) { +TEST_F(ConfigTest, WriterConfigInitialization) +{ // Test with memory writer { WriterConfig writerConfig(WriterTypes::Memory); @@ -77,7 +86,8 @@ TEST_F(ConfigTest, WriterConfigInitialization) { } // Test extra tags handling -TEST_F(ConfigTest, ExtraTags) { +TEST_F(ConfigTest, ExtraTags) +{ WriterConfig writerConfig(WriterTypes::Memory); // Empty tags @@ -88,12 +98,8 @@ TEST_F(ConfigTest, ExtraTags) { // Valid tags { - std::unordered_map tags = - { - {"app", "test-app"}, - {"env", "testing"}, - {"region", "us-east-1"} - }; + std::unordered_map tags = { + {"app", "test-app"}, {"env", "testing"}, {"region", "us-east-1"}}; Config config(writerConfig, tags); @@ -105,12 +111,8 @@ TEST_F(ConfigTest, ExtraTags) { // Invalid tags (empty keys or values should be ignored) { - std::unordered_map tags = - { - {"valid", "value"}, - {"", "empty-key"}, - {"empty-value", ""} - }; + std::unordered_map tags = { + {"valid", "value"}, {"", "empty-key"}, {"empty-value", ""}}; Config config(writerConfig, tags); @@ -122,7 +124,8 @@ TEST_F(ConfigTest, ExtraTags) { } // Test environment variable integration -TEST_F(ConfigTest, EnvironmentVariables) { +TEST_F(ConfigTest, EnvironmentVariables) +{ WriterConfig writerConfig(WriterTypes::Memory); // No environment variables - already unset in SetUp() @@ -135,7 +138,7 @@ TEST_F(ConfigTest, EnvironmentVariables) { { containerGuard.setValue("test-container"); // Process already unset from SetUp() - + Config config(writerConfig); EXPECT_EQ(config.GetExtraTags().size(), 1); @@ -167,7 +170,8 @@ TEST_F(ConfigTest, EnvironmentVariables) { } // Test merging of environment variables and explicit tags -TEST_F(ConfigTest, MergingTags) { +TEST_F(ConfigTest, MergingTags) +{ WriterConfig writerConfig(WriterTypes::Memory); // Environment variables with additional tags @@ -175,11 +179,7 @@ TEST_F(ConfigTest, MergingTags) { containerGuard.setValue("test-container"); processGuard.setValue("test-process"); - std::unordered_map tags = - { - {"custom", "value"}, - {"env", "test"} - }; + std::unordered_map tags = {{"custom", "value"}, {"env", "test"}}; Config config(writerConfig, tags); @@ -195,9 +195,7 @@ TEST_F(ConfigTest, MergingTags) { containerGuard.setValue("test-container"); processGuard.unsetValue(); - std::unordered_map tags = { - {"nf.container", "override-container"} - }; + std::unordered_map tags = {{"nf.container", "override-container"}}; Config config(writerConfig, tags); diff --git a/libs/logger/logger.h b/libs/logger/logger.h index 36ff640..1449ebe 100644 --- a/libs/logger/logger.h +++ b/libs/logger/logger.h @@ -11,12 +11,12 @@ #include #include -constexpr const char *kMainLogger = "spectator"; +constexpr const char* kMainLogger = "spectator"; class Logger final : public Singleton { - private: - spdlog::logger *m_logger; // Use raw pointer, not unique_ptr + private: + spdlog::logger* m_logger; // Use raw pointer, not unique_ptr friend class Singleton; @@ -26,67 +26,56 @@ class Logger final : public Singleton { spdlog::init_thread_pool(8192, 1); auto sink = std::make_shared(); - auto shared_logger = - std::make_shared(kMainLogger, sink, spdlog::thread_pool(), spdlog::async_overflow_policy::block); + auto shared_logger = std::make_shared(kMainLogger, sink, spdlog::thread_pool(), + spdlog::async_overflow_policy::block); shared_logger->set_level(spdlog::level::debug); spdlog::register_logger(shared_logger); m_logger = shared_logger.get(); } - catch (const spdlog::spdlog_ex &ex) + catch (const spdlog::spdlog_ex& ex) { std::cerr << "Log initialization failed: " << ex.what() << "\n"; m_logger = nullptr; } } - ~Logger() = default; - Logger(const Logger &) = delete; - Logger &operator=(const Logger &) = delete; - Logger(Logger &&) = delete; - Logger &operator=(Logger &&) = delete; + ~Logger() = default; + Logger(const Logger&) = delete; + Logger& operator=(const Logger&) = delete; + Logger(Logger&&) = delete; + Logger& operator=(Logger&&) = delete; - public: - static spdlog::logger *GetLogger() - { - return GetInstance().m_logger; - } + public: + static spdlog::logger* GetLogger() { return GetInstance().m_logger; } - static void debug(const std::string &msg) - { - GetLogger()->debug(msg); - } + static void debug(const std::string& msg) { GetLogger()->debug(msg); } - static void info(const std::string &msg) - { - GetLogger()->info(msg); - } + static void info(const std::string& msg) { GetLogger()->info(msg); } - static void warn(const std::string &msg) - { - GetLogger()->warn(msg); - } + static void warn(const std::string& msg) { GetLogger()->warn(msg); } - static void error(const std::string &msg) - { - GetLogger()->error(msg); - } + static void error(const std::string& msg) { GetLogger()->error(msg); } - template static void debug(fmt::format_string fmt, Args &&...args) + template + static void debug(fmt::format_string fmt, Args&&... args) { GetLogger()->debug(fmt, std::forward(args)...); } - template static void info(fmt::format_string fmt, Args &&...args) + template + static void info(fmt::format_string fmt, Args&&... args) { GetLogger()->info(fmt, std::forward(args)...); } - template static void warn(fmt::format_string fmt, Args &&...args) + template + static void warn(fmt::format_string fmt, Args&&... args) { GetLogger()->warn(fmt, std::forward(args)...); } - template static void error(fmt::format_string fmt, Args &&...args) + template + static void error(fmt::format_string fmt, Args&&... args) { GetLogger()->error(fmt, std::forward(args)...); } diff --git a/libs/meter/meter_id/include/meter_id.h b/libs/meter/meter_id/include/meter_id.h index 18a895f..d546abf 100644 --- a/libs/meter/meter_id/include/meter_id.h +++ b/libs/meter/meter_id/include/meter_id.h @@ -8,29 +8,29 @@ class MeterId { - public: - MeterId(const std::string &name, const std::unordered_map &tags = {}); + public: + MeterId(const std::string& name, const std::unordered_map& tags = {}); - const std::string &GetName() const noexcept { return m_name; }; - const std::string &GetSpectatordId() const noexcept { return m_spectatord_id; } - const std::unordered_map &GetTags() const noexcept { return m_tags; }; + const std::string& GetName() const noexcept { return m_name; }; + const std::string& GetSpectatordId() const noexcept { return m_spectatord_id; } + const std::unordered_map& GetTags() const noexcept { return m_tags; }; - MeterId WithTag(const std::string &key, const std::string &value) const; + MeterId WithTag(const std::string& key, const std::string& value) const; - MeterId WithTags(const std::unordered_map &additional_tags) const; + MeterId WithTags(const std::unordered_map& additional_tags) const; - bool operator==(const MeterId &other) const; + bool operator==(const MeterId& other) const; std::string to_string() const; - private: + private: std::string m_name; std::unordered_map m_tags; std::string m_spectatord_id; }; - -template <> struct std::hash +template <> +struct std::hash { - size_t operator()(const MeterId &id) const; + size_t operator()(const MeterId& id) const; }; diff --git a/libs/meter/meter_id/src/meter_id.cpp b/libs/meter/meter_id/src/meter_id.cpp index 61611ae..6fa062e 100644 --- a/libs/meter/meter_id/src/meter_id.cpp +++ b/libs/meter/meter_id/src/meter_id.cpp @@ -6,11 +6,11 @@ // Define the static member const std::regex INVALID_CHARS("[^-._A-Za-z0-9~^]"); -std::unordered_map ValidateTags(const std::unordered_map &tags) +std::unordered_map ValidateTags(const std::unordered_map& tags) { std::unordered_map validTags{}; - for (const auto &[key, value] : tags) + for (const auto& [key, value] : tags) { if (key.empty() == false && value.empty() == false) { @@ -21,18 +21,15 @@ std::unordered_map ValidateTags(const std::unordered_m return validTags; } -std::string RepleaceInvalidChars(const std::string &s) -{ - return std::regex_replace(s, INVALID_CHARS, "_"); -} +std::string RepleaceInvalidChars(const std::string& s) { return std::regex_replace(s, INVALID_CHARS, "_"); } -std::string ToSpectatorId(const std::string &name, const std::unordered_map &tags) +std::string ToSpectatorId(const std::string& name, const std::unordered_map& tags) { std::ostringstream ss; ss << RepleaceInvalidChars(name); if (!tags.empty()) { - for (const auto &tag : tags) + for (const auto& tag : tags) { ss << "," << RepleaceInvalidChars(tag.first) << "=" << RepleaceInvalidChars(tag.second); } @@ -40,40 +37,37 @@ std::string ToSpectatorId(const std::string &name, const std::unordered_map &tags) +MeterId::MeterId(const std::string& name, const std::unordered_map& tags) : m_name(name), m_tags(ValidateTags(tags)) { m_spectatord_id = ToSpectatorId(name, tags); } -MeterId MeterId::WithTag(const std::string &key, const std::string &value) const +MeterId MeterId::WithTag(const std::string& key, const std::string& value) const { auto new_tags = m_tags; new_tags[key] = value; return MeterId(m_name, new_tags); } -MeterId MeterId::WithTags(const std::unordered_map &additional_tags) const +MeterId MeterId::WithTags(const std::unordered_map& additional_tags) const { auto new_tags = m_tags; - for (const auto &pair : additional_tags) + for (const auto& pair : additional_tags) { new_tags[pair.first] = pair.second; } return MeterId(m_name, new_tags); } -bool MeterId::operator==(const MeterId &other) const -{ - return m_name == other.m_name && m_tags == other.m_tags; -} +bool MeterId::operator==(const MeterId& other) const { return m_name == other.m_name && m_tags == other.m_tags; } std::string MeterId::to_string() const { std::ostringstream ss; ss << "MeterId(name=" << m_name << ", tags={"; bool first = true; - for (const auto &pair : m_tags) + for (const auto& pair : m_tags) { if (!first) { @@ -86,17 +80,15 @@ std::string MeterId::to_string() const return ss.str(); } - - // Implementation of the hash function for MeterId -size_t std::hash::operator()(const MeterId &id) const +size_t std::hash::operator()(const MeterId& id) const { // Hash the name first size_t name_hash = std::hash{}(id.GetName()); // Hash the tags size_t tags_hash = 0; - for (const auto &tag : id.GetTags()) + for (const auto& tag : id.GetTags()) { // Combine key and value hashes size_t pair_hash = std::hash{}(tag.first) ^ (std::hash{}(tag.second) << 1); @@ -107,4 +99,3 @@ size_t std::hash::operator()(const MeterId &id) const // Combine name hash and tags hash return name_hash ^ (tags_hash << 1); } - diff --git a/libs/meter/meter_id/test/test_meter_id.cpp b/libs/meter/meter_id/test/test_meter_id.cpp index 9638ea4..3d4714e 100644 --- a/libs/meter/meter_id/test/test_meter_id.cpp +++ b/libs/meter/meter_id/test/test_meter_id.cpp @@ -78,8 +78,8 @@ TEST(MeterIdTest, Tags) TEST(MeterIdTest, TagsDefensiveCopy) { MeterId id1("foo", {{"a", "1"}}); - auto tags = id1.GetTags(); - tags["b"] = "2"; + auto tags = id1.GetTags(); + tags["b"] = "2"; std::unordered_map expected = {{"a", "1"}, {"b", "2"}}; EXPECT_EQ(expected, tags); std::unordered_map expected_original = {{"a", "1"}}; diff --git a/libs/meter/meter_types/include/age_gauge.h b/libs/meter/meter_types/include/age_gauge.h index 230443a..e129585 100644 --- a/libs/meter/meter_types/include/age_gauge.h +++ b/libs/meter/meter_types/include/age_gauge.h @@ -10,10 +10,8 @@ static constexpr auto AGE_GAUGE_TYPE_SYMBOL = "A"; class AgeGauge final : public Meter { - public: - explicit AgeGauge(const MeterId &meter_id) : Meter(meter_id, AGE_GAUGE_TYPE_SYMBOL) - { - } + public: + explicit AgeGauge(const MeterId& meter_id) : Meter(meter_id, AGE_GAUGE_TYPE_SYMBOL) {} void Now() { @@ -21,9 +19,10 @@ class AgeGauge final : public Meter Writer::GetInstance().Write(line); } - void Set(const int &seconds) + void Set(const int& seconds) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(seconds); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + + std::to_string(seconds); Writer::GetInstance().Write(line); } }; diff --git a/libs/meter/meter_types/include/base/meter.h b/libs/meter/meter_types/include/base/meter.h index 4401d74..6728d3c 100644 --- a/libs/meter/meter_types/include/base/meter.h +++ b/libs/meter/meter_types/include/base/meter.h @@ -5,25 +5,20 @@ class Meter { - public: + public: static constexpr auto FIELD_SEPARATOR = ":"; - Meter(const MeterId &meter_id, const std::string &meter_type_symbol) : m_id(meter_id), m_meterTypeSymbol(meter_type_symbol) + Meter(const MeterId& meter_id, const std::string& meter_type_symbol) + : m_id(meter_id), m_meterTypeSymbol(meter_type_symbol) { } virtual ~Meter() = default; - const MeterId &GetId() const noexcept - { - return m_id; - } + const MeterId& GetId() const noexcept { return m_id; } - const std::string &GetMeterTypeSymbol() const noexcept - { - return m_meterTypeSymbol; - } + const std::string& GetMeterTypeSymbol() const noexcept { return m_meterTypeSymbol; } - protected: + protected: MeterId m_id; std::string m_meterTypeSymbol; }; diff --git a/libs/meter/meter_types/include/counter.h b/libs/meter/meter_types/include/counter.h index 8860fcc..d4a73aa 100644 --- a/libs/meter/meter_types/include/counter.h +++ b/libs/meter/meter_types/include/counter.h @@ -10,16 +10,15 @@ static constexpr auto COUNTER_TYPE_SYMBOL = "c"; class Counter final : public Meter { - public: - explicit Counter(const MeterId &meter_id) : Meter(meter_id, COUNTER_TYPE_SYMBOL) - { - } + public: + explicit Counter(const MeterId& meter_id) : Meter(meter_id, COUNTER_TYPE_SYMBOL) {} - void Increment(const double &delta = 1) + void Increment(const double& delta = 1) { if (delta > 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(delta); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + + std::to_string(delta); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/dist_summary.h b/libs/meter/meter_types/include/dist_summary.h index a965e46..a5df77b 100644 --- a/libs/meter/meter_types/include/dist_summary.h +++ b/libs/meter/meter_types/include/dist_summary.h @@ -10,16 +10,15 @@ static constexpr auto DisTRIBUTION_SUMMARY_TYPE_SYMBOL = "d"; class DistributionSummary final : public Meter { - public: - explicit DistributionSummary(const MeterId &meter_id) : Meter(meter_id, DisTRIBUTION_SUMMARY_TYPE_SYMBOL) - { - } + public: + explicit DistributionSummary(const MeterId& meter_id) : Meter(meter_id, DisTRIBUTION_SUMMARY_TYPE_SYMBOL) {} - void Record(const int &amount) + void Record(const int& amount) { if (amount >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(amount); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + + std::to_string(amount); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/gauge.h b/libs/meter/meter_types/include/gauge.h index 59ec1d3..1d96877 100644 --- a/libs/meter/meter_types/include/gauge.h +++ b/libs/meter/meter_types/include/gauge.h @@ -11,16 +11,18 @@ static constexpr auto GAUGE_TYPE_SYMBOL = "g"; class Gauge final : public Meter { - public: - explicit Gauge(const MeterId &meter_id, const std::optional &ttl_seconds = std::nullopt) - : Meter(meter_id, - ttl_seconds.has_value() ? GAUGE_TYPE_SYMBOL + std::string(",") + std::to_string(ttl_seconds.value()) : GAUGE_TYPE_SYMBOL) + public: + explicit Gauge(const MeterId& meter_id, const std::optional& ttl_seconds = std::nullopt) + : Meter(meter_id, ttl_seconds.has_value() + ? GAUGE_TYPE_SYMBOL + std::string(",") + std::to_string(ttl_seconds.value()) + : GAUGE_TYPE_SYMBOL) { } - void Set(const double &value) + void Set(const double& value) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(value); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + + std::to_string(value); Writer::GetInstance().Write(line); } }; \ No newline at end of file diff --git a/libs/meter/meter_types/include/max_gauge.h b/libs/meter/meter_types/include/max_gauge.h index e6700d7..0de9f6e 100644 --- a/libs/meter/meter_types/include/max_gauge.h +++ b/libs/meter/meter_types/include/max_gauge.h @@ -10,14 +10,13 @@ static constexpr auto MAX_GAUGE_TYPE_SYMBOL = "m"; class MaxGauge final : public Meter { - public: - explicit MaxGauge(const MeterId &meter_id) : Meter(meter_id, MAX_GAUGE_TYPE_SYMBOL) - { - } + public: + explicit MaxGauge(const MeterId& meter_id) : Meter(meter_id, MAX_GAUGE_TYPE_SYMBOL) {} - void Set(const double &value) + void Set(const double& value) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(value); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + + std::to_string(value); Writer::GetInstance().Write(line); } }; \ No newline at end of file diff --git a/libs/meter/meter_types/include/monotonic_counter.h b/libs/meter/meter_types/include/monotonic_counter.h index 3c61b4a..5c64f7e 100644 --- a/libs/meter/meter_types/include/monotonic_counter.h +++ b/libs/meter/meter_types/include/monotonic_counter.h @@ -10,14 +10,13 @@ static constexpr auto MONOTONIC_COUNTER_TYPE_SYMBOL = "C"; class MonotonicCounter final : public Meter { - public: - explicit MonotonicCounter(const MeterId &meter_id) : Meter(meter_id, MONOTONIC_COUNTER_TYPE_SYMBOL) - { - } + public: + explicit MonotonicCounter(const MeterId& meter_id) : Meter(meter_id, MONOTONIC_COUNTER_TYPE_SYMBOL) {} - void Set(const double &amount) + void Set(const double& amount) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(amount); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + + std::to_string(amount); Writer::GetInstance().Write(line); } }; diff --git a/libs/meter/meter_types/include/monotonic_counter_uint.h b/libs/meter/meter_types/include/monotonic_counter_uint.h index bd1b114..d88eb27 100644 --- a/libs/meter/meter_types/include/monotonic_counter_uint.h +++ b/libs/meter/meter_types/include/monotonic_counter_uint.h @@ -10,14 +10,13 @@ static constexpr auto MONOTONIC_COUNTER_UINT_TYPE_SYMBOL = "U"; class MonotonicCounterUint final : public Meter { - public: - explicit MonotonicCounterUint(const MeterId &meter_id) : Meter(meter_id, MONOTONIC_COUNTER_UINT_TYPE_SYMBOL) - { - } + public: + explicit MonotonicCounterUint(const MeterId& meter_id) : Meter(meter_id, MONOTONIC_COUNTER_UINT_TYPE_SYMBOL) {} - void Set(const uint64_t &amount) + void Set(const uint64_t& amount) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(amount); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + + std::to_string(amount); Writer::GetInstance().Write(line); } }; diff --git a/libs/meter/meter_types/include/percentile_dist_summary.h b/libs/meter/meter_types/include/percentile_dist_summary.h index ca44cb4..0af7933 100644 --- a/libs/meter/meter_types/include/percentile_dist_summary.h +++ b/libs/meter/meter_types/include/percentile_dist_summary.h @@ -10,17 +10,18 @@ static constexpr auto PERCENTILE_DISTRIBUTION_SUMMARY_TYPE_SYMBOL = "D"; class PercentileDistributionSummary final : public Meter { - public: - explicit PercentileDistributionSummary(const MeterId &meter_id) + public: + explicit PercentileDistributionSummary(const MeterId& meter_id) : Meter(meter_id, PERCENTILE_DISTRIBUTION_SUMMARY_TYPE_SYMBOL) { } - void Record(const int &amount) + void Record(const int& amount) { if (amount >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(amount); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + + std::to_string(amount); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/percentile_timer.h b/libs/meter/meter_types/include/percentile_timer.h index 270b016..282bd16 100644 --- a/libs/meter/meter_types/include/percentile_timer.h +++ b/libs/meter/meter_types/include/percentile_timer.h @@ -10,16 +10,15 @@ static constexpr auto PERCENTILE_TIMER_TYPE_SYMBOL = "T"; class PercentileTimer final : public Meter { - public: - explicit PercentileTimer(const MeterId &meter_id) : Meter(meter_id, PERCENTILE_TIMER_TYPE_SYMBOL) - { - } + public: + explicit PercentileTimer(const MeterId& meter_id) : Meter(meter_id, PERCENTILE_TIMER_TYPE_SYMBOL) {} - void Record(const double &seconds) + void Record(const double& seconds) { if (seconds >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(seconds); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + + std::to_string(seconds); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/timer.h b/libs/meter/meter_types/include/timer.h index e787cc2..9f86a9d 100644 --- a/libs/meter/meter_types/include/timer.h +++ b/libs/meter/meter_types/include/timer.h @@ -10,16 +10,15 @@ static constexpr auto TIMER_TYPE_SYMBOL = "t"; class Timer final : public Meter { - public: - explicit Timer(const MeterId &meter_id) : Meter(meter_id, TIMER_TYPE_SYMBOL) - { - } + public: + explicit Timer(const MeterId& meter_id) : Meter(meter_id, TIMER_TYPE_SYMBOL) {} - void Record(const double &seconds) + void Record(const double& seconds) { if (seconds >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + std::to_string(seconds); + auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + + std::to_string(seconds); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/test/test_age_gauge.cpp b/libs/meter/meter_types/test/test_age_gauge.cpp index 56198b1..31ab552 100644 --- a/libs/meter/meter_types/test/test_age_gauge.cpp +++ b/libs/meter/meter_types/test/test_age_gauge.cpp @@ -5,14 +5,14 @@ class AgeGaugeTest : public ::testing::Test { - protected: + protected: MeterId tid = MeterId("age_gauge"); }; TEST_F(AgeGaugeTest, Now) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); AgeGauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Now(); @@ -22,7 +22,7 @@ TEST_F(AgeGaugeTest, Now) TEST_F(AgeGaugeTest, Set) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); AgeGauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Set(10); diff --git a/libs/meter/meter_types/test/test_counter.cpp b/libs/meter/meter_types/test/test_counter.cpp index c31948c..23a6c31 100644 --- a/libs/meter/meter_types/test/test_counter.cpp +++ b/libs/meter/meter_types/test/test_counter.cpp @@ -5,14 +5,14 @@ class CounterTest : public ::testing::Test { - protected: + protected: MeterId tid = MeterId("counter"); }; TEST_F(CounterTest, increment) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Counter c(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -25,7 +25,7 @@ TEST_F(CounterTest, increment) TEST_F(CounterTest, incrementNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Counter c(tid); c.Increment(-1); diff --git a/libs/meter/meter_types/test/test_dist_summary.cpp b/libs/meter/meter_types/test/test_dist_summary.cpp index 21cccae..bd4627f 100644 --- a/libs/meter/meter_types/test/test_dist_summary.cpp +++ b/libs/meter/meter_types/test/test_dist_summary.cpp @@ -5,14 +5,14 @@ class DistSummaryTest : public ::testing::Test { - protected: + protected: MeterId tid = MeterId("dist_summary"); }; TEST_F(DistSummaryTest, record) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); DistributionSummary ds(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -23,7 +23,7 @@ TEST_F(DistSummaryTest, record) TEST_F(DistSummaryTest, recordNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); DistributionSummary ds(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -34,7 +34,7 @@ TEST_F(DistSummaryTest, recordNegative) TEST_F(DistSummaryTest, recordZero) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); DistributionSummary ds(tid); EXPECT_TRUE(writer->IsEmpty()); diff --git a/libs/meter/meter_types/test/test_gauge.cpp b/libs/meter/meter_types/test/test_gauge.cpp index d0c5d4e..eb3ef5a 100644 --- a/libs/meter/meter_types/test/test_gauge.cpp +++ b/libs/meter/meter_types/test/test_gauge.cpp @@ -5,14 +5,14 @@ class GaugeTest : public ::testing::Test { - protected: + protected: MeterId tid = MeterId("gauge"); }; TEST_F(GaugeTest, Now) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Gauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Set(1); @@ -21,10 +21,10 @@ TEST_F(GaugeTest, Now) TEST_F(GaugeTest, TTL) { - WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); - Gauge g(tid, 10); - EXPECT_TRUE(writer->IsEmpty()); - g.Set(42); - EXPECT_EQ("g,10:gauge:42.000000", writer->LastLine()); + WriterTestHelper::InitializeWriter(WriterType::Memory); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + Gauge g(tid, 10); + EXPECT_TRUE(writer->IsEmpty()); + g.Set(42); + EXPECT_EQ("g,10:gauge:42.000000", writer->LastLine()); } \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_max_gauge.cpp b/libs/meter/meter_types/test/test_max_gauge.cpp index 1598d64..2a7aa93 100644 --- a/libs/meter/meter_types/test/test_max_gauge.cpp +++ b/libs/meter/meter_types/test/test_max_gauge.cpp @@ -5,14 +5,14 @@ class MaxGaugeTest : public ::testing::Test { - protected: + protected: MeterId tid = MeterId("max_gauge"); }; TEST_F(MaxGaugeTest, Set) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); MaxGauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Set(0); diff --git a/libs/meter/meter_types/test/test_monotonic_counter.cpp b/libs/meter/meter_types/test/test_monotonic_counter.cpp index 7e19de6..168c972 100644 --- a/libs/meter/meter_types/test/test_monotonic_counter.cpp +++ b/libs/meter/meter_types/test/test_monotonic_counter.cpp @@ -5,14 +5,14 @@ class MonotonicCounterTest : public ::testing::Test { - protected: + protected: MeterId tid = MeterId("monotonic_counter"); }; TEST_F(MonotonicCounterTest, SetValue) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); MonotonicCounter mc(tid); EXPECT_TRUE(writer->IsEmpty()); mc.Set(1); @@ -22,7 +22,7 @@ TEST_F(MonotonicCounterTest, SetValue) TEST_F(MonotonicCounterTest, SetNegativeValue) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); MonotonicCounter mc(tid); EXPECT_TRUE(writer->IsEmpty()); mc.Set(-1); diff --git a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp index 61580f4..badf481 100644 --- a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp +++ b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp @@ -5,14 +5,14 @@ class MonoCounterTest : public ::testing::Test { - protected: + protected: MeterId tid = MeterId("monotonic_counter_uint"); }; TEST_F(MonoCounterTest, set) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); MonotonicCounterUint mc(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -23,7 +23,7 @@ TEST_F(MonoCounterTest, set) TEST_F(MonoCounterTest, setNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); MonotonicCounterUint mc(tid); EXPECT_TRUE(writer->IsEmpty()); diff --git a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp index 9235c2f..f727e11 100644 --- a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp +++ b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp @@ -5,14 +5,14 @@ class PercentileDistSummaryTest : public ::testing::Test { - protected: + protected: MeterId tid = MeterId("percentile_dist_summary"); }; TEST_F(PercentileDistSummaryTest, record) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileDistributionSummary pds(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -23,7 +23,7 @@ TEST_F(PercentileDistSummaryTest, record) TEST_F(PercentileDistSummaryTest, recordNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileDistributionSummary pds(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -34,7 +34,7 @@ TEST_F(PercentileDistSummaryTest, recordNegative) TEST_F(PercentileDistSummaryTest, recordZero) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileDistributionSummary pds(tid); EXPECT_TRUE(writer->IsEmpty()); diff --git a/libs/meter/meter_types/test/test_percentile_timer.cpp b/libs/meter/meter_types/test/test_percentile_timer.cpp index 5616ce0..5eda430 100644 --- a/libs/meter/meter_types/test/test_percentile_timer.cpp +++ b/libs/meter/meter_types/test/test_percentile_timer.cpp @@ -5,14 +5,14 @@ class PercentileTimerTest : public ::testing::Test { - protected: + protected: MeterId tid = MeterId("percentile_timer"); }; TEST_F(PercentileTimerTest, record) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileTimer pt(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -23,7 +23,7 @@ TEST_F(PercentileTimerTest, record) TEST_F(PercentileTimerTest, recordNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileTimer pt(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -34,7 +34,7 @@ TEST_F(PercentileTimerTest, recordNegative) TEST_F(PercentileTimerTest, recordZero) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileTimer pt(tid); EXPECT_TRUE(writer->IsEmpty()); diff --git a/libs/meter/meter_types/test/test_timer.cpp b/libs/meter/meter_types/test/test_timer.cpp index df885d2..5c6bbd7 100644 --- a/libs/meter/meter_types/test/test_timer.cpp +++ b/libs/meter/meter_types/test/test_timer.cpp @@ -5,14 +5,14 @@ class TimerTest : public ::testing::Test { - protected: + protected: MeterId tid = MeterId("timer"); }; TEST_F(TimerTest, record) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Timer t(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -23,7 +23,7 @@ TEST_F(TimerTest, record) TEST_F(TimerTest, recordNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Timer t(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -34,7 +34,7 @@ TEST_F(TimerTest, recordNegative) TEST_F(TimerTest, recordZero) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto *writer = dynamic_cast(WriterTestHelper::GetImpl()); + auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Timer t(tid); EXPECT_TRUE(writer->IsEmpty()); diff --git a/libs/utils/include/singleton.h b/libs/utils/include/singleton.h index 5be62b3..3f1a300 100644 --- a/libs/utils/include/singleton.h +++ b/libs/utils/include/singleton.h @@ -1,20 +1,21 @@ #pragma once // Templated Singleton for derived singleton classes -template class Singleton +template +class Singleton { - protected: + protected: // Protected constructor & destructor allow derived classes to instantiate - Singleton() = default; + Singleton() = default; virtual ~Singleton() = default; - public: + public: // Prevent copying - Singleton(const Singleton &) = delete; - Singleton &operator=(const Singleton &) = delete; + Singleton(const Singleton&) = delete; + Singleton& operator=(const Singleton&) = delete; // Get the singleton instance - static T &GetInstance() + static T& GetInstance() { static T instance; return instance; diff --git a/libs/utils/include/util.h b/libs/utils/include/util.h index 238b70e..b94f1ea 100644 --- a/libs/utils/include/util.h +++ b/libs/utils/include/util.h @@ -11,7 +11,7 @@ struct ProtocolLine MeterId id; std::string value; - bool operator==(const ProtocolLine &other) const + bool operator==(const ProtocolLine& other) const { return symbol == other.symbol && id == other.id && value == other.value; } @@ -29,7 +29,7 @@ struct ProtocolLine { ss << ","; bool first = true; - for (const auto &[key, value] : sorted_tags) + for (const auto& [key, value] : sorted_tags) { if (!first) { @@ -47,4 +47,4 @@ struct ProtocolLine } }; -std::optional ParseProtocolLine(const std::string &line); \ No newline at end of file +std::optional ParseProtocolLine(const std::string& line); \ No newline at end of file diff --git a/libs/utils/src/util.cpp b/libs/utils/src/util.cpp index 7d3723c..52aa9ca 100644 --- a/libs/utils/src/util.cpp +++ b/libs/utils/src/util.cpp @@ -4,7 +4,7 @@ #include // Utility: split a string by a delimiter -std::vector split(const std::string &str, char delimiter) +std::vector split(const std::string& str, char delimiter) { std::vector tokens; std::stringstream ss(str); @@ -16,11 +16,11 @@ std::vector split(const std::string &str, char delimiter) return tokens; } -std::optional ParseProtocolLine(const std::string &line) +std::optional ParseProtocolLine(const std::string& line) { - char symbol{}; + char symbol{}; std::string name{}; - std::unordered_map tags{}; + std::unordered_map tags{}; std::string value{}; auto mainParts = split(line, ':'); diff --git a/libs/writer/writer_config/include/writer_config.h b/libs/writer/writer_config/include/writer_config.h index ad372f6..8fffd93 100644 --- a/libs/writer/writer_config/include/writer_config.h +++ b/libs/writer/writer_config/include/writer_config.h @@ -8,14 +8,14 @@ class WriterConfig { - public: - WriterConfig(const std::string &type); + public: + WriterConfig(const std::string& type); - const WriterType &GetType() const noexcept { return m_type; }; + const WriterType& GetType() const noexcept { return m_type; }; - const std::string &GetLocation() const noexcept { return m_location;}; + const std::string& GetLocation() const noexcept { return m_location; }; - private: - WriterType m_type; - std::string m_location; + private: + WriterType m_type; + std::string m_location; }; \ No newline at end of file diff --git a/libs/writer/writer_config/src/writer_config.cpp b/libs/writer/writer_config/src/writer_config.cpp index 1cecec7..ffc0764 100644 --- a/libs/writer/writer_config/src/writer_config.cpp +++ b/libs/writer/writer_config/src/writer_config.cpp @@ -5,7 +5,7 @@ struct WriterConfigConstants static constexpr auto RuntimeErrorMessage = "Invalid writer type: "; }; -std::pair GetWriterConfigFromString(const std::string &type) +std::pair GetWriterConfigFromString(const std::string& type) { // Check exact matches first auto it = TypeToLocationMap.find(type); @@ -18,7 +18,7 @@ std::pair GetWriterConfigFromString(const std::string & { return {WriterType::UDP, type}; } - + if (type.rfind(WriterTypes::UnixURL, 0) == 0) { return {WriterType::Unix, type}; @@ -27,23 +27,23 @@ std::pair GetWriterConfigFromString(const std::string & throw std::runtime_error(WriterConfigConstants::RuntimeErrorMessage + type); } -WriterConfig::WriterConfig(const std::string &type) +WriterConfig::WriterConfig(const std::string& type) { - const char *envLocation = std::getenv("SPECTATOR_OUTPUT_LOCATION"); + const char* envLocation = std::getenv("SPECTATOR_OUTPUT_LOCATION"); if (envLocation != nullptr) { Logger::debug("Using environment variable SPECTATOR_OUTPUT_LOCATION: {}", envLocation); std::string envValue(envLocation); auto [writer_type, location] = GetWriterConfigFromString(envValue); - m_type = writer_type; - m_location = location; + m_type = writer_type; + m_location = location; } else { Logger::debug("Using provided type: {}", type); auto [writer_type, location] = GetWriterConfigFromString(type); - m_type = writer_type; - m_location = location; + m_type = writer_type; + m_location = location; } - Logger::debug("WriterConfig initialized with type: {}, location: {}", WriterTypeToString(m_type), m_location); + Logger::debug("WriterConfig initialized with type: {}, location: {}", WriterTypeToString(m_type), m_location); } \ No newline at end of file diff --git a/libs/writer/writer_config/test/test_writer_config.cpp b/libs/writer/writer_config/test/test_writer_config.cpp index fd8ee66..43d7880 100644 --- a/libs/writer/writer_config/test/test_writer_config.cpp +++ b/libs/writer/writer_config/test/test_writer_config.cpp @@ -9,45 +9,44 @@ // Enhanced helper to temporarily modify an environment variable for testing class EnvironmentVariableGuard { -public: - - EnvironmentVariableGuard(const std::string& name) : m_name(name) + public: + EnvironmentVariableGuard(const std::string& name) : m_name(name) { - if (const char* value = std::getenv(name.c_str())) + if (const char* value = std::getenv(name.c_str())) { m_originalValue = value; } } - void setValue(const std::string& value) - { - setenv(m_name.c_str(), value.c_str(), 1); - } + void setValue(const std::string& value) { setenv(m_name.c_str(), value.c_str(), 1); } void unsetValue() { unsetenv(m_name.c_str()); } - ~EnvironmentVariableGuard() + ~EnvironmentVariableGuard() { - if (m_originalValue.has_value()) { setenv(m_name.c_str(), m_originalValue->c_str(), 1); } - else { unsetenv(m_name.c_str()); } + if (m_originalValue.has_value()) + { + setenv(m_name.c_str(), m_originalValue->c_str(), 1); + } + else + { + unsetenv(m_name.c_str()); + } } -private: + private: std::string m_name; std::optional m_originalValue; }; -class WriterConfigTest : public ::testing::Test { -protected: +class WriterConfigTest : public ::testing::Test +{ + protected: EnvironmentVariableGuard envGuard{"SPECTATOR_OUTPUT_LOCATION"}; - void SetUp() override - { - envGuard.unsetValue(); - } + void SetUp() override { envGuard.unsetValue(); } }; - TEST_F(WriterConfigTest, BasicWriterTypes) { // Test "memory" type @@ -72,7 +71,6 @@ TEST_F(WriterConfigTest, BasicWriterTypes) } } - TEST_F(WriterConfigTest, URLBasedWriterTypes) { // Test UDP URL @@ -96,11 +94,11 @@ TEST_F(WriterConfigTest, EnvironmentVariableOverride) { { envGuard.setValue(WriterTypes::Memory); - WriterConfig config(WriterTypes::UDP); // This should be ignored due to env var + WriterConfig config(WriterTypes::UDP); // This should be ignored due to env var EXPECT_EQ(config.GetType(), WriterType::Memory); EXPECT_EQ(config.GetLocation(), DefaultLocations::NoLocation); } - + { envGuard.unsetValue(); WriterConfig config(WriterTypes::Memory); @@ -116,13 +114,12 @@ TEST_F(WriterConfigTest, InvalidWriterType) { envGuard.setValue("invalid_env_value"); - EXPECT_THROW({WriterConfig config(WriterTypes::Memory);}, std::runtime_error); + EXPECT_THROW({ WriterConfig config(WriterTypes::Memory); }, std::runtime_error); } } TEST_F(WriterConfigTest, EdgeCases) { - // Test with just URL scheme but no path { WriterConfig config("udp://"); diff --git a/libs/writer/writer_types/include/base/base_writer.h b/libs/writer/writer_types/include/base/base_writer.h index 3b7ca8b..f1e88bd 100644 --- a/libs/writer/writer_types/include/base/base_writer.h +++ b/libs/writer/writer_types/include/base/base_writer.h @@ -4,15 +4,15 @@ class BaseWriter { - public: - BaseWriter() = default; + public: + BaseWriter() = default; virtual ~BaseWriter() = default; - BaseWriter(const BaseWriter &) = delete; - BaseWriter &operator=(const BaseWriter &) = delete; - BaseWriter(BaseWriter &&) = delete; - BaseWriter &operator=(BaseWriter &&) = delete; + BaseWriter(const BaseWriter&) = delete; + BaseWriter& operator=(const BaseWriter&) = delete; + BaseWriter(BaseWriter&&) = delete; + BaseWriter& operator=(BaseWriter&&) = delete; - virtual void Write(const std::string &message) = 0; - virtual void Close() = 0; + virtual void Write(const std::string& message) = 0; + virtual void Close() = 0; }; \ No newline at end of file diff --git a/libs/writer/writer_types/include/memory_writer.h b/libs/writer/writer_types/include/memory_writer.h index 757b064..62e386d 100644 --- a/libs/writer/writer_types/include/memory_writer.h +++ b/libs/writer/writer_types/include/memory_writer.h @@ -6,23 +6,20 @@ class MemoryWriter final : public BaseWriter { - public: - MemoryWriter() = default; + public: + MemoryWriter() = default; ~MemoryWriter() override = default; - void Write(const std::string &message) override; + void Write(const std::string& message) override; void Close() override; void Clear(); - const std::vector &GetMessages() const noexcept - { - return m_messages; - } + const std::vector& GetMessages() const noexcept { return m_messages; } - const std::string &LastLine() const noexcept; - - bool IsEmpty() const noexcept { return m_messages.empty(); } + const std::string& LastLine() const noexcept; - private: + bool IsEmpty() const noexcept { return m_messages.empty(); } + + private: std::vector m_messages; }; diff --git a/libs/writer/writer_types/include/udp_writer.h b/libs/writer/writer_types/include/udp_writer.h index 4f10cdb..c3a71c3 100644 --- a/libs/writer/writer_types/include/udp_writer.h +++ b/libs/writer/writer_types/include/udp_writer.h @@ -7,13 +7,13 @@ class UDPWriter final : public BaseWriter { - public: - UDPWriter(const std::string &host, int port); + public: + UDPWriter(const std::string& host, int port); ~UDPWriter() override; - void Write(const std::string &message) override; + void Write(const std::string& message) override; void Close() override; - private: + private: std::string m_host; int m_port; std::unique_ptr m_io_context; diff --git a/libs/writer/writer_types/include/uds_writer.h b/libs/writer/writer_types/include/uds_writer.h index 9ac404b..c2ec150 100644 --- a/libs/writer/writer_types/include/uds_writer.h +++ b/libs/writer/writer_types/include/uds_writer.h @@ -8,13 +8,13 @@ class UDSWriter final : public BaseWriter { - public: - UDSWriter(const std::string &socketPath); + public: + UDSWriter(const std::string& socketPath); ~UDSWriter() override; - void Write(const std::string &message) override; + void Write(const std::string& message) override; void Close() override; - private: + private: std::string m_socketPath; std::unique_ptr m_ioContext; std::unique_ptr m_socket; diff --git a/libs/writer/writer_types/include/writer_types.h b/libs/writer/writer_types/include/writer_types.h index 96a05c6..69dce83 100644 --- a/libs/writer/writer_types/include/writer_types.h +++ b/libs/writer/writer_types/include/writer_types.h @@ -21,19 +21,19 @@ enum class WriterType struct WriterTypes { static constexpr auto Memory = "memory"; - static constexpr auto UDP = "udp"; - static constexpr auto Unix = "unix"; + static constexpr auto UDP = "udp"; + static constexpr auto Unix = "unix"; // URL prefixes - static constexpr auto UDPURL = "udp://"; + static constexpr auto UDPURL = "udp://"; static constexpr auto UnixURL = "unix://"; }; struct DefaultLocations { static constexpr auto NoLocation = ""; - static constexpr auto UDP = "udp://127.0.0.1:1234"; - static constexpr auto UDS = "unix:///run/spectatord/spectatord.unix"; + static constexpr auto UDP = "udp://127.0.0.1:1234"; + static constexpr auto UDS = "unix:///run/spectatord/spectatord.unix"; }; inline const std::map> TypeToLocationMap = { @@ -42,13 +42,17 @@ inline const std::map> {WriterTypes::Unix, {WriterType::Unix, DefaultLocations::UDS}}, }; -inline std::string WriterTypeToString(WriterType type) +inline std::string WriterTypeToString(WriterType type) { switch (type) { - case WriterType::Memory: return WriterTypes::Memory; - case WriterType::UDP: return WriterTypes::UDP; - case WriterType::Unix: return WriterTypes::Unix; - default: return "Unknown"; + case WriterType::Memory: + return WriterTypes::Memory; + case WriterType::UDP: + return WriterTypes::UDP; + case WriterType::Unix: + return WriterTypes::Unix; + default: + return "Unknown"; } } \ No newline at end of file diff --git a/libs/writer/writer_types/src/memory_writer.cpp b/libs/writer/writer_types/src/memory_writer.cpp index e6b6efe..45a16f4 100644 --- a/libs/writer/writer_types/src/memory_writer.cpp +++ b/libs/writer/writer_types/src/memory_writer.cpp @@ -2,7 +2,7 @@ #include -void MemoryWriter::Write(const std::string &message) +void MemoryWriter::Write(const std::string& message) { this->m_messages.push_back(message); Logger::debug("MemoryWriter::Writing: {}", message); @@ -20,7 +20,7 @@ void MemoryWriter::Clear() Logger::debug("MemoryWriter::Cleared messages"); } -const std::string &MemoryWriter::LastLine() const noexcept +const std::string& MemoryWriter::LastLine() const noexcept { static const std::string emptyString = ""; diff --git a/libs/writer/writer_types/src/udp_writer.cpp b/libs/writer/writer_types/src/udp_writer.cpp index 7a15a6d..9aca429 100644 --- a/libs/writer/writer_types/src/udp_writer.cpp +++ b/libs/writer/writer_types/src/udp_writer.cpp @@ -4,7 +4,7 @@ #include -UDPWriter::UDPWriter(const std::string &host, int port) : m_host(host), m_port(port) +UDPWriter::UDPWriter(const std::string& host, int port) : m_host(host), m_port(port) { try { @@ -19,19 +19,16 @@ UDPWriter::UDPWriter(const std::string &host, int port) : m_host(host), m_port(p boost::asio::ip::udp::resolver resolver(*m_io_context); m_endpoint = *resolver.resolve(boost::asio::ip::udp::v4(), m_host, std::to_string(m_port)).begin(); } - catch (const boost::system::system_error &e) + catch (const boost::system::system_error& e) { Logger::error("UDPWriter: Failed to initialize connection: {}", e.what()); Close(); } } -UDPWriter::~UDPWriter() -{ - Close(); -} +UDPWriter::~UDPWriter() { Close(); } -void UDPWriter::Write(const std::string &message) +void UDPWriter::Write(const std::string& message) try { if (m_socket == nullptr || m_socket->is_open() == false) @@ -52,7 +49,7 @@ try Logger::warn("UDPWriter: Sent only {} bytes out of {} bytes", sent, message.size()); } } -catch (const std::exception &e) +catch (const std::exception& e) { Logger::error("UDPWriter: Exception during write: {}", e.what()); } @@ -60,7 +57,6 @@ catch (const std::exception &e) void UDPWriter::Close() try { - if (m_socket && m_socket->is_open()) { boost::system::error_code ec; @@ -75,7 +71,7 @@ try m_socket.reset(); m_io_context.reset(); } -catch (const std::exception &e) +catch (const std::exception& e) { Logger::error("UDPWriter: Exception during close: {}", e.what()); } \ No newline at end of file diff --git a/libs/writer/writer_types/src/uds_writer.cpp b/libs/writer/writer_types/src/uds_writer.cpp index 4acafa4..4033605 100644 --- a/libs/writer/writer_types/src/uds_writer.cpp +++ b/libs/writer/writer_types/src/uds_writer.cpp @@ -2,30 +2,28 @@ #include - #include #include #include namespace local = boost::asio::local; -UDSWriter::UDSWriter(const std::string &socketPath) - : m_socketPath(socketPath), m_ioContext(std::make_unique()), m_socket(nullptr), +UDSWriter::UDSWriter(const std::string& socketPath) + : m_socketPath(socketPath), + m_ioContext(std::make_unique()), + m_socket(nullptr), m_isOpen(false) { connect(); } -UDSWriter::~UDSWriter() -{ - Close(); -} +UDSWriter::~UDSWriter() { Close(); } bool UDSWriter::connect() { if (m_isOpen) { - return true; // Already connected + return true; // Already connected } try @@ -52,7 +50,7 @@ bool UDSWriter::connect() Logger::debug("UDS Writer: Connected to {}", m_socketPath); return true; } - catch (const std::exception &e) + catch (const std::exception& e) { Logger::error("UDS Writer: Exception while connecting - {}", e.what()); m_isOpen = false; @@ -60,7 +58,7 @@ bool UDSWriter::connect() } } -void UDSWriter::Write(const std::string &message) +void UDSWriter::Write(const std::string& message) { if (!m_isOpen && !connect()) { @@ -76,17 +74,17 @@ void UDSWriter::Write(const std::string &message) if (ec) { Logger::error("UDS Writer: Failed to send message - {}", ec.message()); - m_isOpen = false; // Mark as disconnected on error + m_isOpen = false; // Mark as disconnected on error } else { Logger::debug("UDS Writer: Sent message ({} bytes)", message.size()); } } - catch (const std::exception &e) + catch (const std::exception& e) { Logger::error("UDS Writer: Exception while sending message - {}", e.what()); - m_isOpen = false; // Mark as disconnected on exception + m_isOpen = false; // Mark as disconnected on exception } } @@ -105,7 +103,7 @@ void UDSWriter::Close() Logger::warn("UDS Writer: Error closing socket - {}", ec.message()); } } - catch (const std::exception &e) + catch (const std::exception& e) { Logger::warn("UDS Writer: Exception while closing socket - {}", e.what()); } diff --git a/libs/writer/writer_types/test/test_memory_writer.cpp b/libs/writer/writer_types/test/test_memory_writer.cpp index fb61302..2aa46a2 100644 --- a/libs/writer/writer_types/test/test_memory_writer.cpp +++ b/libs/writer/writer_types/test/test_memory_writer.cpp @@ -31,7 +31,7 @@ TEST(MemoryWriterTest, GetMessages) writer.Write("First message"); writer.Write("Second message"); - const auto &messages = writer.GetMessages(); + const auto& messages = writer.GetMessages(); EXPECT_EQ(messages.size(), 2); EXPECT_EQ(messages[0], "First message"); EXPECT_EQ(messages[1], "Second message"); diff --git a/libs/writer/writer_types/test/test_udp_writer.cpp b/libs/writer/writer_types/test/test_udp_writer.cpp index 152d8cb..e79c682 100644 --- a/libs/writer/writer_types/test/test_udp_writer.cpp +++ b/libs/writer/writer_types/test/test_udp_writer.cpp @@ -2,15 +2,15 @@ #include -#include "../test_utils/udp_server/udp_server.h" // Include our new header for UDP server interaction +#include "../test_utils/udp_server/udp_server.h" // Include our new header for UDP server interaction #include #include -#include // For std::find +#include // For std::find // Test fixture for UDP Writer tests class UDPWriterTest : public ::testing::Test { - protected: + protected: void SetUp() override { // Set the server to run @@ -66,7 +66,7 @@ TEST_F(UDPWriterTest, SendMessage) // Check that our message is in the vector bool message_found = false; - for (const auto &msg : messages) + for (const auto& msg : messages) { if (msg == test_message) { @@ -78,7 +78,6 @@ TEST_F(UDPWriterTest, SendMessage) TEST_F(UDPWriterTest, CloseAndReopen) { - UDPWriter writer("127.0.0.1", 1234); std::string message1 = "Initial message"; writer.Write(message1); @@ -110,14 +109,13 @@ TEST_F(UDPWriterTest, CloseAndReopen) TEST_F(UDPWriterTest, SendMultipleMessages) { - UDPWriter writer("127.0.0.1", 1234); // Define test messages std::vector test_messages = {"Message 1", "Message 2", "Message 3"}; // Send several messages in succession - for (const auto &msg : test_messages) + for (const auto& msg : test_messages) { writer.Write(msg); } diff --git a/libs/writer/writer_types/test/test_uds_writer.cpp b/libs/writer/writer_types/test/test_uds_writer.cpp index 9bc40e9..b5c7dc7 100644 --- a/libs/writer/writer_types/test/test_uds_writer.cpp +++ b/libs/writer/writer_types/test/test_uds_writer.cpp @@ -10,7 +10,7 @@ // Test fixture for UDS Writer tests class UDSWriterTest : public ::testing::Test { - protected: + protected: void SetUp() override { // Set the server to run @@ -66,7 +66,7 @@ TEST_F(UDSWriterTest, SendMessage) // Check that our message is in the vector bool message_found = false; - for (const auto &msg : messages) + for (const auto& msg : messages) { if (msg == test_message) { @@ -117,7 +117,7 @@ TEST_F(UDSWriterTest, SendMultipleMessages) std::vector test_messages = {"Message 1", "Message 2", "Message 3"}; // Send messages one by one, with a separate connection for each - for (const auto &msg : test_messages) + for (const auto& msg : test_messages) { writer.Write(msg); // Wait for the message to be processed diff --git a/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp b/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp index ec4bcf2..b7599d9 100644 --- a/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp +++ b/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp @@ -31,7 +31,7 @@ void clear_messages() messages.clear(); } -void add_message(const std::string &message) +void add_message(const std::string& message) { std::lock_guard lock(messages_mutex); messages.push_back(message); @@ -55,7 +55,7 @@ try socket.bind(endpoint); std::cout << "Socket bound to IPv4 localhost (127.0.0.1):" << port << std::endl; } - catch (const std::exception &e) + catch (const std::exception& e) { std::cerr << "Error binding socket: " << e.what() << "\n"; throw; @@ -92,7 +92,7 @@ try std::cout << "Received from " << sender_endpoint << ": " << message << std::endl; std::cout << "Total messages stored: " << current_messages.size() << std::endl; } - catch (const boost::system::system_error &e) + catch (const boost::system::system_error& e) { if (e.code() == boost::asio::error::would_block) { @@ -108,7 +108,7 @@ try } std::cout << "UDP server shutting down..." << std::endl; } -catch (const std::exception &e) +catch (const std::exception& e) { std::cerr << "Exception in UDP server: " << e.what() << "\n"; return; diff --git a/libs/writer/writer_types/test_utils/udp_server/udp_server.h b/libs/writer/writer_types/test_utils/udp_server/udp_server.h index 2514ec9..76ffac8 100644 --- a/libs/writer/writer_types/test_utils/udp_server/udp_server.h +++ b/libs/writer/writer_types/test_utils/udp_server/udp_server.h @@ -8,7 +8,7 @@ // Functions to interact with the UDP server's message storage std::vector get_messages(); void clear_messages(); -void add_message(const std::string &message); +void add_message(const std::string& message); // Function to run the server in a thread - can be used by both the server executable and tests void listen_for_udp_messages(); diff --git a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp index 173887a..f33774b 100644 --- a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp +++ b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp @@ -35,7 +35,7 @@ void clear_uds_messages() uds_messages.clear(); } -void add_uds_message(const std::string &message) +void add_uds_message(const std::string& message) { std::lock_guard lock(uds_messages_mutex); uds_messages.push_back(message); @@ -124,7 +124,7 @@ try // Close the connection socket.close(); } - catch (const std::exception &e) + catch (const std::exception& e) { std::cerr << "Exception handling client: " << e.what() << std::endl; } @@ -135,7 +135,7 @@ try // Clean up the socket file on exit std::filesystem::remove(socket_path); } -catch (const std::exception &e) +catch (const std::exception& e) { std::cerr << "Exception in UDS server: " << e.what() << std::endl; return; diff --git a/libs/writer/writer_types/test_utils/uds_server/uds_server.h b/libs/writer/writer_types/test_utils/uds_server/uds_server.h index b03873f..cb37eab 100644 --- a/libs/writer/writer_types/test_utils/uds_server/uds_server.h +++ b/libs/writer/writer_types/test_utils/uds_server/uds_server.h @@ -8,7 +8,7 @@ // Functions to interact with the UDS server's message storage std::vector get_uds_messages(); void clear_uds_messages(); -void add_uds_message(const std::string &message); +void add_uds_message(const std::string& message); // Function to run the server in a thread - can be used by both the server executable and tests void listen_for_uds_messages(); diff --git a/libs/writer/writer_wrapper/include/Writer.h b/libs/writer/writer_wrapper/include/Writer.h index 1ffd5f9..fb4c8a8 100644 --- a/libs/writer/writer_wrapper/include/Writer.h +++ b/libs/writer/writer_wrapper/include/Writer.h @@ -6,44 +6,39 @@ #include #include - class Writer final : public Singleton { - public: + public: virtual ~Writer(); - - private: + private: friend class Singleton; friend class Registry; friend class WriterTestHelper; friend class AgeGauge; friend class Counter; - friend class DistributionSummary; - friend class Gauge; - friend class MaxGauge; - friend class MonotonicCounter; - friend class MonotonicCounterUint; - friend class PercentileDistributionSummary; - friend class PercentileTimer; - friend class Timer; + friend class DistributionSummary; + friend class Gauge; + friend class MaxGauge; + friend class MonotonicCounter; + friend class MonotonicCounterUint; + friend class PercentileDistributionSummary; + friend class PercentileTimer; + friend class Timer; // Private constructor - enforces singleton pattern Writer() = default; - static void Initialize(WriterType type, const std::string ¶m = "", int port = 0); - - static void Write(const std::string &message); + static void Initialize(WriterType type, const std::string& param = "", int port = 0); + + static void Write(const std::string& message); static void Close(); static WriterType GetWriterType(); // Get the Writer's implementation for testing purposes - static BaseWriter *GetImpl() - { - return Writer::GetInstance().m_impl.get(); - } + static BaseWriter* GetImpl() { return Writer::GetInstance().m_impl.get(); } /** * Reset the writer to uninitialized state * This method is private and can only be called by Registry @@ -52,5 +47,5 @@ class Writer final : public Singleton // Implementation details std::unique_ptr m_impl; - WriterType m_currentType = WriterType::Memory; // Default type + WriterType m_currentType = WriterType::Memory; // Default type }; \ No newline at end of file diff --git a/libs/writer/writer_wrapper/include/writer_test_helper.h b/libs/writer/writer_wrapper/include/writer_test_helper.h index 81e82cc..aaa5ef9 100644 --- a/libs/writer/writer_wrapper/include/writer_test_helper.h +++ b/libs/writer/writer_wrapper/include/writer_test_helper.h @@ -10,22 +10,16 @@ */ class WriterTestHelper { - public: + public: // Initialize the Writer for testing purposes - static void InitializeWriter(WriterType type, const std::string ¶m = "", int port = 0) + static void InitializeWriter(WriterType type, const std::string& param = "", int port = 0) { Writer::Initialize(type, param, port); } // Reset the Writer for testing purposes - static void ResetWriter() - { - Writer::Reset(); - } + static void ResetWriter() { Writer::Reset(); } // Get the Writer's implementation for testing purposes - static BaseWriter *GetImpl() - { - return Writer::GetInstance().m_impl.get(); - } + static BaseWriter* GetImpl() { return Writer::GetInstance().m_impl.get(); } }; diff --git a/libs/writer/writer_wrapper/src/Writer.cpp b/libs/writer/writer_wrapper/src/Writer.cpp index e1ba3de..669481d 100644 --- a/libs/writer/writer_wrapper/src/Writer.cpp +++ b/libs/writer/writer_wrapper/src/Writer.cpp @@ -9,35 +9,35 @@ Writer::~Writer() // No need to explicitly close here as unique_ptr will clean up } -void Writer::Initialize(WriterType type, const std::string ¶m, int port) +void Writer::Initialize(WriterType type, const std::string& param, int port) { // Get the singleton instance directly - auto &instance = GetInstance(); + auto& instance = GetInstance(); // Create the new writer based on type try { switch (type) { - case WriterType::Memory: - instance.m_impl = std::make_unique(); - Logger::info("Writer initialized as MemoryWriter"); - break; - case WriterType::UDP: - instance.m_impl = std::make_unique(param, port); - Logger::info("Writer initialized as UDPWriter with host: {} and port: {}", param, port); - break; - case WriterType::Unix: - instance.m_impl = std::make_unique(param); - Logger::info("Writer initialized as UnixWriter with socket path: {}", param); - break; - default: - throw std::runtime_error("Unsupported writer type"); + case WriterType::Memory: + instance.m_impl = std::make_unique(); + Logger::info("Writer initialized as MemoryWriter"); + break; + case WriterType::UDP: + instance.m_impl = std::make_unique(param, port); + Logger::info("Writer initialized as UDPWriter with host: {} and port: {}", param, port); + break; + case WriterType::Unix: + instance.m_impl = std::make_unique(param); + Logger::info("Writer initialized as UnixWriter with socket path: {}", param); + break; + default: + throw std::runtime_error("Unsupported writer type"); } instance.m_currentType = type; } - catch (const std::exception &e) + catch (const std::exception& e) { Logger::error("Failed to initialize writer: {}", e.what()); throw; @@ -46,7 +46,7 @@ void Writer::Initialize(WriterType type, const std::string ¶m, int port) void Writer::Reset() { - auto &instance = GetInstance(); + auto& instance = GetInstance(); if (instance.m_impl) { @@ -54,7 +54,7 @@ void Writer::Reset() { instance.m_impl->Close(); } - catch (const std::exception &e) + catch (const std::exception& e) { Logger::warn("Exception while closing writer during reset: {}", e.what()); } @@ -64,9 +64,9 @@ void Writer::Reset() Logger::info("Writer has been reset"); } -void Writer::Write(const std::string &message) +void Writer::Write(const std::string& message) { - auto &instance = GetInstance(); + auto& instance = GetInstance(); if (!instance.m_impl) { @@ -78,7 +78,7 @@ void Writer::Write(const std::string &message) { instance.m_impl->Write(message); } - catch (const std::exception &e) + catch (const std::exception& e) { Logger::error("Write operation failed: {}", e.what()); } @@ -86,7 +86,7 @@ void Writer::Write(const std::string &message) void Writer::Close() { - auto &instance = GetInstance(); + auto& instance = GetInstance(); if (!instance.m_impl) { @@ -99,13 +99,10 @@ void Writer::Close() instance.m_impl->Close(); Logger::debug("Writer closed successfully"); } - catch (const std::exception &e) + catch (const std::exception& e) { Logger::error("Failed to close writer: {}", e.what()); } } -WriterType Writer::GetWriterType() -{ - return GetInstance().m_currentType; -} +WriterType Writer::GetWriterType() { return GetInstance().m_currentType; } diff --git a/requirements.txt b/requirements.txt index b047f71..eba6e90 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -conan==2.16.1 \ No newline at end of file +conan==2.17.1 \ No newline at end of file diff --git a/spectator/include/registry.h b/spectator/include/registry.h index 162fab9..96bba97 100644 --- a/spectator/include/registry.h +++ b/spectator/include/registry.h @@ -3,7 +3,7 @@ #include #include #include -#include // Include Writer.h +#include // Include Writer.h #include #include @@ -14,63 +14,68 @@ class Registry { - public: - explicit Registry(const Config &config); + public: + explicit Registry(const Config& config); ~Registry(); - MeterId new_id(const std::string &name, const std::unordered_map &tags = {}) const; + MeterId new_id(const std::string& name, const std::unordered_map& tags = {}) const; - AgeGauge age_gauge(const std::string &name, - const std::unordered_map &tags = std::unordered_map()); + AgeGauge age_gauge(const std::string& name, const std::unordered_map& tags = + std::unordered_map()); - AgeGauge age_gauge_with_id(const MeterId &meter_id); + AgeGauge age_gauge_with_id(const MeterId& meter_id); - Counter counter(const std::string &name, - const std::unordered_map &tags = std::unordered_map()); + Counter counter(const std::string& name, const std::unordered_map& tags = + std::unordered_map()); - Counter counter_with_id(const MeterId &meter_id); + Counter counter_with_id(const MeterId& meter_id); DistributionSummary distribution_summary( - const std::string &name, const std::unordered_map &tags = std::unordered_map()); + const std::string& name, + const std::unordered_map& tags = std::unordered_map()); - DistributionSummary distribution_summary_with_id(const MeterId &meter_id); + DistributionSummary distribution_summary_with_id(const MeterId& meter_id); - Gauge gauge(const std::string &name, - const std::unordered_map &tags = std::unordered_map(), - const std::optional &ttl_seconds = std::nullopt); + Gauge gauge( + const std::string& name, + const std::unordered_map& tags = std::unordered_map(), + const std::optional& ttl_seconds = std::nullopt); - Gauge gauge_with_id(const MeterId &meter_id, const std::optional &ttl_seconds = std::nullopt); + Gauge gauge_with_id(const MeterId& meter_id, const std::optional& ttl_seconds = std::nullopt); - MaxGauge max_gauge(const std::string &name, - const std::unordered_map &tags = std::unordered_map()); + MaxGauge max_gauge(const std::string& name, const std::unordered_map& tags = + std::unordered_map()); - MaxGauge max_gauge_with_id(const MeterId &meter_id); + MaxGauge max_gauge_with_id(const MeterId& meter_id); MonotonicCounter monotonic_counter( - const std::string &name, const std::unordered_map &tags = std::unordered_map()); + const std::string& name, + const std::unordered_map& tags = std::unordered_map()); - MonotonicCounter monotonic_counter_with_id(const MeterId &meter_id); + MonotonicCounter monotonic_counter_with_id(const MeterId& meter_id); MonotonicCounterUint monotonic_counter_uint( - const std::string &name, const std::unordered_map &tags = std::unordered_map()); + const std::string& name, + const std::unordered_map& tags = std::unordered_map()); - MonotonicCounterUint monotonic_counter_uint_with_id(const MeterId &meter_id); + MonotonicCounterUint monotonic_counter_uint_with_id(const MeterId& meter_id); PercentileDistributionSummary pct_distribution_summary( - const std::string &name, const std::unordered_map &tags = std::unordered_map()); + const std::string& name, + const std::unordered_map& tags = std::unordered_map()); - PercentileDistributionSummary pct_distribution_summary_with_id(const MeterId &meter_id); + PercentileDistributionSummary pct_distribution_summary_with_id(const MeterId& meter_id); - PercentileTimer pct_timer(const std::string &name, - const std::unordered_map &tags = std::unordered_map()); + PercentileTimer pct_timer(const std::string& name, const std::unordered_map& tags = + std::unordered_map()); - PercentileTimer pct_timer_with_id(const MeterId &meter_id); + PercentileTimer pct_timer_with_id(const MeterId& meter_id); - Timer timer(const std::string &name, - const std::unordered_map &tags = std::unordered_map()); + Timer timer(const std::string& name, const std::unordered_map& tags = + std::unordered_map()); - Timer timer_with_id(const MeterId &meter_id); + Timer timer_with_id(const MeterId& meter_id); - private: + private: Config m_config; }; \ No newline at end of file diff --git a/spectator/src/registry.cpp b/spectator/src/registry.cpp index 314fb17..99743f4 100644 --- a/spectator/src/registry.cpp +++ b/spectator/src/registry.cpp @@ -1,9 +1,6 @@ #include -Registry::Registry(const Config &config) : m_config(config) -{ - Writer::Initialize(config.GetWriterType()); -} +Registry::Registry(const Config& config) : m_config(config) { Writer::Initialize(config.GetWriterType()); } Registry::~Registry() { @@ -11,8 +8,7 @@ Registry::~Registry() // and will live beyond Registry instances } - -MeterId Registry::new_id(const std::string &name, const std::unordered_map &tags) const +MeterId Registry::new_id(const std::string& name, const std::unordered_map& tags) const { MeterId new_meter_id(name, tags); @@ -26,104 +22,89 @@ MeterId Registry::new_id(const std::string &name, const std::unordered_map &tags) +AgeGauge Registry::age_gauge(const std::string& name, const std::unordered_map& tags) { return AgeGauge(new_id(name, tags)); } -AgeGauge Registry::age_gauge_with_id(const MeterId &meter_id) -{ - return AgeGauge(meter_id); -} +AgeGauge Registry::age_gauge_with_id(const MeterId& meter_id) { return AgeGauge(meter_id); } -Counter Registry::counter(const std::string &name, const std::unordered_map &tags) +Counter Registry::counter(const std::string& name, const std::unordered_map& tags) { return Counter(new_id(name, tags)); } -Counter Registry::counter_with_id(const MeterId &meter_id) -{ - return Counter(meter_id); -} +Counter Registry::counter_with_id(const MeterId& meter_id) { return Counter(meter_id); } -DistributionSummary Registry::distribution_summary(const std::string &name, const std::unordered_map &tags) +DistributionSummary Registry::distribution_summary(const std::string& name, + const std::unordered_map& tags) { return DistributionSummary(new_id(name, tags)); } -DistributionSummary Registry::distribution_summary_with_id(const MeterId &meter_id) +DistributionSummary Registry::distribution_summary_with_id(const MeterId& meter_id) { return DistributionSummary(meter_id); } -Gauge Registry::gauge(const std::string &name, const std::unordered_map &tags, - const std::optional &ttl_seconds) +Gauge Registry::gauge(const std::string& name, const std::unordered_map& tags, + const std::optional& ttl_seconds) { return Gauge(new_id(name, tags), ttl_seconds); } -Gauge Registry::gauge_with_id(const MeterId &meter_id, const std::optional &ttl_seconds) +Gauge Registry::gauge_with_id(const MeterId& meter_id, const std::optional& ttl_seconds) { return Gauge(meter_id, ttl_seconds); } -MaxGauge Registry::max_gauge(const std::string &name, const std::unordered_map &tags) +MaxGauge Registry::max_gauge(const std::string& name, const std::unordered_map& tags) { return MaxGauge(new_id(name, tags)); } -MaxGauge Registry::max_gauge_with_id(const MeterId &meter_id) -{ - return MaxGauge(meter_id); -} +MaxGauge Registry::max_gauge_with_id(const MeterId& meter_id) { return MaxGauge(meter_id); } -MonotonicCounter Registry::monotonic_counter(const std::string &name, const std::unordered_map &tags) +MonotonicCounter Registry::monotonic_counter(const std::string& name, + const std::unordered_map& tags) { return MonotonicCounter(new_id(name, tags)); } -MonotonicCounter Registry::monotonic_counter_with_id(const MeterId &meter_id) -{ - return MonotonicCounter(meter_id); -} +MonotonicCounter Registry::monotonic_counter_with_id(const MeterId& meter_id) { return MonotonicCounter(meter_id); } -MonotonicCounterUint Registry::monotonic_counter_uint(const std::string &name, const std::unordered_map &tags) +MonotonicCounterUint Registry::monotonic_counter_uint(const std::string& name, + const std::unordered_map& tags) { return MonotonicCounterUint(new_id(name, tags)); } -MonotonicCounterUint Registry::monotonic_counter_uint_with_id(const MeterId &meter_id) +MonotonicCounterUint Registry::monotonic_counter_uint_with_id(const MeterId& meter_id) { return MonotonicCounterUint(meter_id); } -PercentileDistributionSummary Registry::pct_distribution_summary(const std::string &name, - const std::unordered_map &tags) +PercentileDistributionSummary Registry::pct_distribution_summary( + const std::string& name, const std::unordered_map& tags) { return PercentileDistributionSummary(new_id(name, tags)); } -PercentileDistributionSummary Registry::pct_distribution_summary_with_id(const MeterId &meter_id) +PercentileDistributionSummary Registry::pct_distribution_summary_with_id(const MeterId& meter_id) { return PercentileDistributionSummary(meter_id); } -PercentileTimer Registry::pct_timer(const std::string &name, const std::unordered_map &tags) +PercentileTimer Registry::pct_timer(const std::string& name, const std::unordered_map& tags) { return PercentileTimer(new_id(name, tags)); } -PercentileTimer Registry::pct_timer_with_id(const MeterId &meter_id) -{ - return PercentileTimer(meter_id); -} +PercentileTimer Registry::pct_timer_with_id(const MeterId& meter_id) { return PercentileTimer(meter_id); } -Timer Registry::timer(const std::string &name, const std::unordered_map &tags) +Timer Registry::timer(const std::string& name, const std::unordered_map& tags) { return Timer(new_id(name, tags)); } -Timer Registry::timer_with_id(const MeterId &meter_id) -{ - return Timer(meter_id); -} \ No newline at end of file +Timer Registry::timer_with_id(const MeterId& meter_id) { return Timer(meter_id); } \ No newline at end of file diff --git a/spectator/test/test_registry.cpp b/spectator/test/test_registry.cpp index b3dc4c6..eb288c4 100644 --- a/spectator/test/test_registry.cpp +++ b/spectator/test/test_registry.cpp @@ -13,7 +13,7 @@ TEST(RegistryTest, Close) auto c = r.counter("counter"); c.Increment(); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); EXPECT_EQ("c:counter:1.000000", memoryWriter->LastLine()); memoryWriter->Close(); @@ -23,10 +23,10 @@ TEST(RegistryTest, Close) TEST(RegistryTest, AgeGauge) { Config config(WriterConfig(WriterTypes::Memory)); - auto r = Registry(config); - auto g1 = r.age_gauge("age_gauge"); - auto g2 = r.age_gauge("age_gauge", {{"my-tags", "bar"}}); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto g1 = r.age_gauge("age_gauge"); + auto g2 = r.age_gauge("age_gauge", {{"my-tags", "bar"}}); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -40,23 +40,24 @@ TEST(RegistryTest, AgeGauge) TEST(RegistryTest, AgeGaugeWithId) { Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto g = r.age_gauge_with_id(r.new_id("age_gauge", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(0); - EXPECT_EQ("A:age_gauge,extra-tags=foo,my-tags=bar:0", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("A:age_gauge,extra-tags=foo,my-tags=bar:0", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } TEST(RegistryTest, Counter) { Config config(WriterConfig(WriterTypes::Memory)); - auto r = Registry(config); - auto c1 = r.counter("counter"); - auto c2 = r.counter("counter", {{"my-tags", "bar"}}); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto c1 = r.counter("counter"); + auto c2 = r.counter("counter", {{"my-tags", "bar"}}); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -79,27 +80,30 @@ TEST(RegistryTest, Counter) TEST(RegistryTest, CounterWithId) { Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto c = r.counter_with_id(r.new_id("counter", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); c.Increment(); - EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:1.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:1.000000", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); c.Increment(2); - EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:2.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:2.000000", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); r.counter("counter", {{"my-tags", "bar"}}).Increment(3); - EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:3.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:3.000000", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } TEST(RegistryTest, DistributionSummary) { Config config(WriterConfig(WriterTypes::Memory)); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto d = r.distribution_summary("distribution_summary"); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -111,21 +115,22 @@ TEST(RegistryTest, DistributionSummary) TEST(RegistryTest, DistributionSummaryWithId) { Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto d = r.distribution_summary_with_id(r.new_id("distribution_summary", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); d.Record(42); - EXPECT_EQ("d:distribution_summary,extra-tags=foo,my-tags=bar:42", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("d:distribution_summary,extra-tags=foo,my-tags=bar:42", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } TEST(RegistryTest, Gauge) { Config config(WriterConfig(WriterTypes::Memory)); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto g = r.gauge("gauge"); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -137,14 +142,15 @@ TEST(RegistryTest, Gauge) TEST(RegistryTest, GaugeWithId) { Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto g = r.gauge_with_id(r.new_id("gauge", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(42); - EXPECT_EQ("g:gauge,extra-tags=foo,my-tags=bar:42.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("g:gauge,extra-tags=foo,my-tags=bar:42.000000", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } TEST(RegistryTest, GaugeWithIdWithTtlSeconds) @@ -175,8 +181,8 @@ TEST(RegistryTest, GaugeWithIdWithTtlSeconds) TEST(RegistryTest, MaxGauge) { Config config(WriterConfig(WriterTypes::Memory)); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto g = r.max_gauge("max_gauge"); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -188,21 +194,22 @@ TEST(RegistryTest, MaxGauge) TEST(RegistryTest, MaxGaugeWithId) { Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto g = r.max_gauge_with_id(r.new_id("max_gauge", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(42); - EXPECT_EQ("m:max_gauge,extra-tags=foo,my-tags=bar:42.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("m:max_gauge,extra-tags=foo,my-tags=bar:42.000000", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } TEST(RegistryTest, MonotonicCounter) { Config config(WriterConfig(WriterTypes::Memory)); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto c = r.monotonic_counter("monotonic_counter"); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -214,21 +221,22 @@ TEST(RegistryTest, MonotonicCounter) TEST(RegistryTest, MonotonicCounterWithId) { Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto c = r.monotonic_counter_with_id(r.new_id("monotonic_counter", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); c.Set(42); - EXPECT_EQ("C:monotonic_counter,extra-tags=foo,my-tags=bar:42.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("C:monotonic_counter,extra-tags=foo,my-tags=bar:42.000000", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } TEST(RegistryTest, MonotonicCounterUint) { Config config(WriterConfig(WriterTypes::Memory)); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto c = r.monotonic_counter_uint("monotonic_counter_uint"); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -240,25 +248,26 @@ TEST(RegistryTest, MonotonicCounterUint) TEST(RegistryTest, MonotonicCounterUintWithId) { Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto c = r.monotonic_counter_uint_with_id(r.new_id("monotonic_counter_uint", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); c.Set(42); - EXPECT_EQ("U:monotonic_counter_uint,extra-tags=foo,my-tags=bar:42", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("U:monotonic_counter_uint,extra-tags=foo,my-tags=bar:42", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } TEST(RegistryTest, NewId) { Config config1(WriterConfig(WriterTypes::Memory)); - auto r1 = Registry(config1); + auto r1 = Registry(config1); auto id1 = r1.new_id("id"); EXPECT_EQ("MeterId(name=id, tags={})", id1.to_string()); Config config2(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r2 = Registry(config2); + auto r2 = Registry(config2); auto id2 = r2.new_id("id"); EXPECT_EQ("MeterId(name=id, tags={'extra-tags': 'foo'})", id2.to_string()); } @@ -266,8 +275,8 @@ TEST(RegistryTest, NewId) TEST(RegistryTest, PctDistributionSummary) { Config config(WriterConfig(WriterTypes::Memory)); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto d = r.pct_distribution_summary("pct_distribution_summary"); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -279,21 +288,22 @@ TEST(RegistryTest, PctDistributionSummary) TEST(RegistryTest, PctDistributionSummaryWithId) { Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto d = r.pct_distribution_summary_with_id(r.new_id("pct_distribution_summary", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); d.Record(42); - EXPECT_EQ("D:pct_distribution_summary,extra-tags=foo,my-tags=bar:42", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("D:pct_distribution_summary,extra-tags=foo,my-tags=bar:42", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } TEST(RegistryTest, PctTimer) { Config config(WriterConfig(WriterTypes::Memory)); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto t = r.pct_timer("pct_timer"); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -305,21 +315,22 @@ TEST(RegistryTest, PctTimer) TEST(RegistryTest, PctTimerWithId) { Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto t = r.pct_timer_with_id(r.new_id("pct_timer", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); t.Record(42); - EXPECT_EQ("T:pct_timer,extra-tags=foo,my-tags=bar:42.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("T:pct_timer,extra-tags=foo,my-tags=bar:42.000000", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } TEST(RegistryTest, Timer) { Config config(WriterConfig(WriterTypes::Memory)); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto t = r.timer("timer"); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -331,12 +342,13 @@ TEST(RegistryTest, Timer) TEST(RegistryTest, TimerWithId) { Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); - auto r = Registry(config); - auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); auto t = r.timer_with_id(r.new_id("timer", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); t.Record(42); - EXPECT_EQ("t:timer,extra-tags=foo,my-tags=bar:42.000000", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); + EXPECT_EQ("t:timer,extra-tags=foo,my-tags=bar:42.000000", + ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } \ No newline at end of file From 174bcdc642fa2d5b5dc7d450def068dbd973871b Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Sun, 15 Jun 2025 22:20:30 -0500 Subject: [PATCH 07/34] reorg meter_id --- libs/meter/meter_id/CMakeLists.txt | 4 ++-- libs/meter/meter_id/{src => }/meter_id.cpp | 2 +- libs/meter/meter_id/{include => }/meter_id.h | 0 libs/meter/meter_id/{test => }/test_meter_id.cpp | 2 +- libs/meter/meter_types/include/age_gauge.h | 2 +- libs/meter/meter_types/include/base/meter.h | 2 +- libs/meter/meter_types/include/counter.h | 2 +- libs/meter/meter_types/include/dist_summary.h | 2 +- libs/meter/meter_types/include/gauge.h | 2 +- libs/meter/meter_types/include/max_gauge.h | 2 +- libs/meter/meter_types/include/monotonic_counter.h | 2 +- libs/meter/meter_types/include/monotonic_counter_uint.h | 2 +- libs/meter/meter_types/include/percentile_dist_summary.h | 2 +- libs/meter/meter_types/include/percentile_timer.h | 2 +- libs/meter/meter_types/include/timer.h | 2 +- libs/utils/include/util.h | 5 ++++- spectator/include/registry.h | 2 +- 17 files changed, 20 insertions(+), 17 deletions(-) rename libs/meter/meter_id/{src => }/meter_id.cpp (98%) rename libs/meter/meter_id/{include => }/meter_id.h (100%) rename libs/meter/meter_id/{test => }/test_meter_id.cpp (98%) diff --git a/libs/meter/meter_id/CMakeLists.txt b/libs/meter/meter_id/CMakeLists.txt index 255cd06..803c03e 100644 --- a/libs/meter/meter_id/CMakeLists.txt +++ b/libs/meter/meter_id/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(spectator-meter-id - src/meter_id.cpp + meter_id.cpp ) target_include_directories(spectator-meter-id @@ -8,7 +8,7 @@ target_include_directories(spectator-meter-id ) add_executable(MeterID-test - test/test_meter_id.cpp + test_meter_id.cpp ) target_link_libraries(MeterID-test PRIVATE diff --git a/libs/meter/meter_id/src/meter_id.cpp b/libs/meter/meter_id/meter_id.cpp similarity index 98% rename from libs/meter/meter_id/src/meter_id.cpp rename to libs/meter/meter_id/meter_id.cpp index 6fa062e..7006d87 100644 --- a/libs/meter/meter_id/src/meter_id.cpp +++ b/libs/meter/meter_id/meter_id.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/libs/meter/meter_id/include/meter_id.h b/libs/meter/meter_id/meter_id.h similarity index 100% rename from libs/meter/meter_id/include/meter_id.h rename to libs/meter/meter_id/meter_id.h diff --git a/libs/meter/meter_id/test/test_meter_id.cpp b/libs/meter/meter_id/test_meter_id.cpp similarity index 98% rename from libs/meter/meter_id/test/test_meter_id.cpp rename to libs/meter/meter_id/test_meter_id.cpp index 3d4714e..31820f9 100644 --- a/libs/meter/meter_id/test/test_meter_id.cpp +++ b/libs/meter/meter_id/test_meter_id.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/libs/meter/meter_types/include/age_gauge.h b/libs/meter/meter_types/include/age_gauge.h index e129585..3626fed 100644 --- a/libs/meter/meter_types/include/age_gauge.h +++ b/libs/meter/meter_types/include/age_gauge.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/libs/meter/meter_types/include/base/meter.h b/libs/meter/meter_types/include/base/meter.h index 6728d3c..86a0317 100644 --- a/libs/meter/meter_types/include/base/meter.h +++ b/libs/meter/meter_types/include/base/meter.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include class Meter diff --git a/libs/meter/meter_types/include/counter.h b/libs/meter/meter_types/include/counter.h index d4a73aa..618a421 100644 --- a/libs/meter/meter_types/include/counter.h +++ b/libs/meter/meter_types/include/counter.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/libs/meter/meter_types/include/dist_summary.h b/libs/meter/meter_types/include/dist_summary.h index a5df77b..b9b12df 100644 --- a/libs/meter/meter_types/include/dist_summary.h +++ b/libs/meter/meter_types/include/dist_summary.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/libs/meter/meter_types/include/gauge.h b/libs/meter/meter_types/include/gauge.h index 1d96877..52a2898 100644 --- a/libs/meter/meter_types/include/gauge.h +++ b/libs/meter/meter_types/include/gauge.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/libs/meter/meter_types/include/max_gauge.h b/libs/meter/meter_types/include/max_gauge.h index 0de9f6e..4ee36cc 100644 --- a/libs/meter/meter_types/include/max_gauge.h +++ b/libs/meter/meter_types/include/max_gauge.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/libs/meter/meter_types/include/monotonic_counter.h b/libs/meter/meter_types/include/monotonic_counter.h index 5c64f7e..5209182 100644 --- a/libs/meter/meter_types/include/monotonic_counter.h +++ b/libs/meter/meter_types/include/monotonic_counter.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/libs/meter/meter_types/include/monotonic_counter_uint.h b/libs/meter/meter_types/include/monotonic_counter_uint.h index d88eb27..7e9a16d 100644 --- a/libs/meter/meter_types/include/monotonic_counter_uint.h +++ b/libs/meter/meter_types/include/monotonic_counter_uint.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/libs/meter/meter_types/include/percentile_dist_summary.h b/libs/meter/meter_types/include/percentile_dist_summary.h index 0af7933..29c897f 100644 --- a/libs/meter/meter_types/include/percentile_dist_summary.h +++ b/libs/meter/meter_types/include/percentile_dist_summary.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/libs/meter/meter_types/include/percentile_timer.h b/libs/meter/meter_types/include/percentile_timer.h index 282bd16..4d670ed 100644 --- a/libs/meter/meter_types/include/percentile_timer.h +++ b/libs/meter/meter_types/include/percentile_timer.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/libs/meter/meter_types/include/timer.h b/libs/meter/meter_types/include/timer.h index 9f86a9d..fb26f78 100644 --- a/libs/meter/meter_types/include/timer.h +++ b/libs/meter/meter_types/include/timer.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/libs/utils/include/util.h b/libs/utils/include/util.h index b94f1ea..4a9139e 100644 --- a/libs/utils/include/util.h +++ b/libs/utils/include/util.h @@ -1,10 +1,13 @@ +# pragma once + #include #include #include #include #include -#include +#include + struct ProtocolLine { char symbol; diff --git a/spectator/include/registry.h b/spectator/include/registry.h index 96bba97..848bccf 100644 --- a/spectator/include/registry.h +++ b/spectator/include/registry.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include // Include Writer.h From 01c14f47e8a14e8b5bcf18e5c1635f71bef2b0de Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Sun, 15 Jun 2025 22:23:36 -0500 Subject: [PATCH 08/34] reorg config --- libs/config/CMakeLists.txt | 4 ++-- libs/config/{src => }/config.cpp | 2 +- libs/config/{include => }/config.h | 0 libs/config/{test => }/test_config.cpp | 2 +- spectator/include/registry.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename libs/config/{src => }/config.cpp (96%) rename libs/config/{include => }/config.h (100%) rename libs/config/{test => }/test_config.cpp (99%) diff --git a/libs/config/CMakeLists.txt b/libs/config/CMakeLists.txt index 6c1682a..ad90c6b 100644 --- a/libs/config/CMakeLists.txt +++ b/libs/config/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(spectator-config - src/config.cpp + config.cpp ) target_include_directories(spectator-config @@ -12,7 +12,7 @@ target_link_libraries(spectator-config ) add_executable(config-tests - test/test_config.cpp + test_config.cpp ) target_link_libraries(config-tests PRIVATE diff --git a/libs/config/src/config.cpp b/libs/config/config.cpp similarity index 96% rename from libs/config/src/config.cpp rename to libs/config/config.cpp index db5ecbf..9c052fc 100644 --- a/libs/config/src/config.cpp +++ b/libs/config/config.cpp @@ -1,4 +1,4 @@ -#include +#include struct ConfigConstants { diff --git a/libs/config/include/config.h b/libs/config/config.h similarity index 100% rename from libs/config/include/config.h rename to libs/config/config.h diff --git a/libs/config/test/test_config.cpp b/libs/config/test_config.cpp similarity index 99% rename from libs/config/test/test_config.cpp rename to libs/config/test_config.cpp index 6f495f5..90010d5 100644 --- a/libs/config/test/test_config.cpp +++ b/libs/config/test_config.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include // Enhanced helper to temporarily modify an environment variable for testing diff --git a/spectator/include/registry.h b/spectator/include/registry.h index 848bccf..adbb490 100644 --- a/spectator/include/registry.h +++ b/spectator/include/registry.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include // Include Writer.h From be945230a797cf27135393ceb71e05277e03a584 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Sun, 15 Jun 2025 22:29:54 -0500 Subject: [PATCH 09/34] remove base folders --- libs/meter/meter_types/include/age_gauge.h | 2 +- libs/meter/meter_types/include/counter.h | 2 +- libs/meter/meter_types/include/dist_summary.h | 2 +- libs/meter/meter_types/include/gauge.h | 2 +- libs/meter/meter_types/include/max_gauge.h | 2 +- libs/meter/meter_types/include/{base => }/meter.h | 0 libs/meter/meter_types/include/monotonic_counter.h | 2 +- libs/meter/meter_types/include/monotonic_counter_uint.h | 2 +- libs/meter/meter_types/include/percentile_dist_summary.h | 2 +- libs/meter/meter_types/include/percentile_timer.h | 2 +- libs/meter/meter_types/include/timer.h | 2 +- libs/writer/writer_types/include/{base => }/base_writer.h | 0 libs/writer/writer_types/include/memory_writer.h | 2 +- libs/writer/writer_types/include/udp_writer.h | 2 +- libs/writer/writer_types/include/uds_writer.h | 2 +- 15 files changed, 13 insertions(+), 13 deletions(-) rename libs/meter/meter_types/include/{base => }/meter.h (100%) rename libs/writer/writer_types/include/{base => }/base_writer.h (100%) diff --git a/libs/meter/meter_types/include/age_gauge.h b/libs/meter/meter_types/include/age_gauge.h index 3626fed..392c461 100644 --- a/libs/meter/meter_types/include/age_gauge.h +++ b/libs/meter/meter_types/include/age_gauge.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/meter/meter_types/include/counter.h b/libs/meter/meter_types/include/counter.h index 618a421..21ae605 100644 --- a/libs/meter/meter_types/include/counter.h +++ b/libs/meter/meter_types/include/counter.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/meter/meter_types/include/dist_summary.h b/libs/meter/meter_types/include/dist_summary.h index b9b12df..50b0e25 100644 --- a/libs/meter/meter_types/include/dist_summary.h +++ b/libs/meter/meter_types/include/dist_summary.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/meter/meter_types/include/gauge.h b/libs/meter/meter_types/include/gauge.h index 52a2898..2c17937 100644 --- a/libs/meter/meter_types/include/gauge.h +++ b/libs/meter/meter_types/include/gauge.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/meter/meter_types/include/max_gauge.h b/libs/meter/meter_types/include/max_gauge.h index 4ee36cc..2436382 100644 --- a/libs/meter/meter_types/include/max_gauge.h +++ b/libs/meter/meter_types/include/max_gauge.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/meter/meter_types/include/base/meter.h b/libs/meter/meter_types/include/meter.h similarity index 100% rename from libs/meter/meter_types/include/base/meter.h rename to libs/meter/meter_types/include/meter.h diff --git a/libs/meter/meter_types/include/monotonic_counter.h b/libs/meter/meter_types/include/monotonic_counter.h index 5209182..5784abc 100644 --- a/libs/meter/meter_types/include/monotonic_counter.h +++ b/libs/meter/meter_types/include/monotonic_counter.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/meter/meter_types/include/monotonic_counter_uint.h b/libs/meter/meter_types/include/monotonic_counter_uint.h index 7e9a16d..45bbe49 100644 --- a/libs/meter/meter_types/include/monotonic_counter_uint.h +++ b/libs/meter/meter_types/include/monotonic_counter_uint.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/meter/meter_types/include/percentile_dist_summary.h b/libs/meter/meter_types/include/percentile_dist_summary.h index 29c897f..f100cd0 100644 --- a/libs/meter/meter_types/include/percentile_dist_summary.h +++ b/libs/meter/meter_types/include/percentile_dist_summary.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/meter/meter_types/include/percentile_timer.h b/libs/meter/meter_types/include/percentile_timer.h index 4d670ed..ffd2d64 100644 --- a/libs/meter/meter_types/include/percentile_timer.h +++ b/libs/meter/meter_types/include/percentile_timer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/meter/meter_types/include/timer.h b/libs/meter/meter_types/include/timer.h index fb26f78..2d1de17 100644 --- a/libs/meter/meter_types/include/timer.h +++ b/libs/meter/meter_types/include/timer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/writer/writer_types/include/base/base_writer.h b/libs/writer/writer_types/include/base_writer.h similarity index 100% rename from libs/writer/writer_types/include/base/base_writer.h rename to libs/writer/writer_types/include/base_writer.h diff --git a/libs/writer/writer_types/include/memory_writer.h b/libs/writer/writer_types/include/memory_writer.h index 62e386d..32d38fe 100644 --- a/libs/writer/writer_types/include/memory_writer.h +++ b/libs/writer/writer_types/include/memory_writer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/writer/writer_types/include/udp_writer.h b/libs/writer/writer_types/include/udp_writer.h index c3a71c3..0615f34 100644 --- a/libs/writer/writer_types/include/udp_writer.h +++ b/libs/writer/writer_types/include/udp_writer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include diff --git a/libs/writer/writer_types/include/uds_writer.h b/libs/writer/writer_types/include/uds_writer.h index c2ec150..5707577 100644 --- a/libs/writer/writer_types/include/uds_writer.h +++ b/libs/writer/writer_types/include/uds_writer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include From b5c092e3b10b7c3400c3dd8a34e29cd444c24da3 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Sun, 15 Jun 2025 22:34:40 -0500 Subject: [PATCH 10/34] remove excess folders writer_config --- libs/config/config.h | 2 +- libs/writer/writer_config/CMakeLists.txt | 6 +++--- libs/writer/writer_config/{test => }/test_writer_config.cpp | 2 +- libs/writer/writer_config/{src => }/writer_config.cpp | 2 +- libs/writer/writer_config/{include => }/writer_config.h | 0 5 files changed, 6 insertions(+), 6 deletions(-) rename libs/writer/writer_config/{test => }/test_writer_config.cpp (98%) rename libs/writer/writer_config/{src => }/writer_config.cpp (95%) rename libs/writer/writer_config/{include => }/writer_config.h (100%) diff --git a/libs/config/config.h b/libs/config/config.h index 9b8cd4c..97a76af 100644 --- a/libs/config/config.h +++ b/libs/config/config.h @@ -3,7 +3,7 @@ #include #include -#include +#include class Config { diff --git a/libs/writer/writer_config/CMakeLists.txt b/libs/writer/writer_config/CMakeLists.txt index 8200620..20c2f6a 100644 --- a/libs/writer/writer_config/CMakeLists.txt +++ b/libs/writer/writer_config/CMakeLists.txt @@ -1,6 +1,6 @@ add_library(spectator-writer-config STATIC - src/writer_config.cpp - include/writer_config.h + writer_config.cpp + writer_config.h ) target_include_directories(spectator-writer-config @@ -16,7 +16,7 @@ target_link_libraries(spectator-writer-config ) add_executable(test_writer_config - test/test_writer_config.cpp) + test_writer_config.cpp) target_link_libraries(test_writer_config PRIVATE diff --git a/libs/writer/writer_config/test/test_writer_config.cpp b/libs/writer/writer_config/test_writer_config.cpp similarity index 98% rename from libs/writer/writer_config/test/test_writer_config.cpp rename to libs/writer/writer_config/test_writer_config.cpp index 43d7880..8cd75ef 100644 --- a/libs/writer/writer_config/test/test_writer_config.cpp +++ b/libs/writer/writer_config/test_writer_config.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/libs/writer/writer_config/src/writer_config.cpp b/libs/writer/writer_config/writer_config.cpp similarity index 95% rename from libs/writer/writer_config/src/writer_config.cpp rename to libs/writer/writer_config/writer_config.cpp index ffc0764..69441e4 100644 --- a/libs/writer/writer_config/src/writer_config.cpp +++ b/libs/writer/writer_config/writer_config.cpp @@ -1,4 +1,4 @@ -#include +#include struct WriterConfigConstants { diff --git a/libs/writer/writer_config/include/writer_config.h b/libs/writer/writer_config/writer_config.h similarity index 100% rename from libs/writer/writer_config/include/writer_config.h rename to libs/writer/writer_config/writer_config.h From 27253bd91e1031272c3495a9865711b0a77def56 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Mon, 16 Jun 2025 00:36:37 -0500 Subject: [PATCH 11/34] flatten project --- libs/meter/meter_types/include/age_gauge.h | 2 +- libs/meter/meter_types/include/counter.h | 2 +- libs/meter/meter_types/include/dist_summary.h | 2 +- libs/meter/meter_types/include/gauge.h | 2 +- libs/meter/meter_types/include/max_gauge.h | 2 +- libs/meter/meter_types/include/monotonic_counter.h | 2 +- libs/meter/meter_types/include/monotonic_counter_uint.h | 2 +- libs/meter/meter_types/include/percentile_dist_summary.h | 2 +- libs/meter/meter_types/include/percentile_timer.h | 2 +- libs/meter/meter_types/include/timer.h | 2 +- libs/meter/meter_types/test/test_age_gauge.cpp | 2 +- libs/meter/meter_types/test/test_counter.cpp | 2 +- libs/meter/meter_types/test/test_dist_summary.cpp | 2 +- libs/meter/meter_types/test/test_gauge.cpp | 2 +- libs/meter/meter_types/test/test_max_gauge.cpp | 2 +- libs/meter/meter_types/test/test_monotonic_counter.cpp | 2 +- libs/meter/meter_types/test/test_monotonic_counter_uint.cpp | 2 +- libs/meter/meter_types/test/test_percentile_dist_summary.cpp | 2 +- libs/meter/meter_types/test/test_percentile_timer.cpp | 2 +- libs/meter/meter_types/test/test_timer.cpp | 2 +- libs/writer/writer_wrapper/CMakeLists.txt | 2 +- libs/writer/writer_wrapper/{src/Writer.cpp => writer.cpp} | 2 +- libs/writer/writer_wrapper/{include/Writer.h => writer.h} | 0 libs/writer/writer_wrapper/{include => }/writer_test_helper.h | 2 +- spectator/CMakeLists.txt | 4 ++-- spectator/{src => }/registry.cpp | 2 +- spectator/{include => }/registry.h | 2 +- spectator/{test => }/test_registry.cpp | 4 ++-- 28 files changed, 29 insertions(+), 29 deletions(-) rename libs/writer/writer_wrapper/{src/Writer.cpp => writer.cpp} (97%) rename libs/writer/writer_wrapper/{include/Writer.h => writer.h} (100%) rename libs/writer/writer_wrapper/{include => }/writer_test_helper.h (92%) rename spectator/{src => }/registry.cpp (98%) rename spectator/{include => }/registry.h (97%) rename spectator/{test => }/test_registry.cpp (99%) diff --git a/libs/meter/meter_types/include/age_gauge.h b/libs/meter/meter_types/include/age_gauge.h index 392c461..b84647a 100644 --- a/libs/meter/meter_types/include/age_gauge.h +++ b/libs/meter/meter_types/include/age_gauge.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/libs/meter/meter_types/include/counter.h b/libs/meter/meter_types/include/counter.h index 21ae605..0105f26 100644 --- a/libs/meter/meter_types/include/counter.h +++ b/libs/meter/meter_types/include/counter.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/libs/meter/meter_types/include/dist_summary.h b/libs/meter/meter_types/include/dist_summary.h index 50b0e25..6180307 100644 --- a/libs/meter/meter_types/include/dist_summary.h +++ b/libs/meter/meter_types/include/dist_summary.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/libs/meter/meter_types/include/gauge.h b/libs/meter/meter_types/include/gauge.h index 2c17937..d135dca 100644 --- a/libs/meter/meter_types/include/gauge.h +++ b/libs/meter/meter_types/include/gauge.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include diff --git a/libs/meter/meter_types/include/max_gauge.h b/libs/meter/meter_types/include/max_gauge.h index 2436382..61ea1bd 100644 --- a/libs/meter/meter_types/include/max_gauge.h +++ b/libs/meter/meter_types/include/max_gauge.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/libs/meter/meter_types/include/monotonic_counter.h b/libs/meter/meter_types/include/monotonic_counter.h index 5784abc..c5f72e2 100644 --- a/libs/meter/meter_types/include/monotonic_counter.h +++ b/libs/meter/meter_types/include/monotonic_counter.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/libs/meter/meter_types/include/monotonic_counter_uint.h b/libs/meter/meter_types/include/monotonic_counter_uint.h index 45bbe49..79aad7a 100644 --- a/libs/meter/meter_types/include/monotonic_counter_uint.h +++ b/libs/meter/meter_types/include/monotonic_counter_uint.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/libs/meter/meter_types/include/percentile_dist_summary.h b/libs/meter/meter_types/include/percentile_dist_summary.h index f100cd0..87b52ba 100644 --- a/libs/meter/meter_types/include/percentile_dist_summary.h +++ b/libs/meter/meter_types/include/percentile_dist_summary.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/libs/meter/meter_types/include/percentile_timer.h b/libs/meter/meter_types/include/percentile_timer.h index ffd2d64..037bad5 100644 --- a/libs/meter/meter_types/include/percentile_timer.h +++ b/libs/meter/meter_types/include/percentile_timer.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/libs/meter/meter_types/include/timer.h b/libs/meter/meter_types/include/timer.h index 2d1de17..8dccdfd 100644 --- a/libs/meter/meter_types/include/timer.h +++ b/libs/meter/meter_types/include/timer.h @@ -2,7 +2,7 @@ #include #include -#include +#include #include diff --git a/libs/meter/meter_types/test/test_age_gauge.cpp b/libs/meter/meter_types/test/test_age_gauge.cpp index 31ab552..3be0eea 100644 --- a/libs/meter/meter_types/test/test_age_gauge.cpp +++ b/libs/meter/meter_types/test/test_age_gauge.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/libs/meter/meter_types/test/test_counter.cpp b/libs/meter/meter_types/test/test_counter.cpp index 23a6c31..dcccb69 100644 --- a/libs/meter/meter_types/test/test_counter.cpp +++ b/libs/meter/meter_types/test/test_counter.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/libs/meter/meter_types/test/test_dist_summary.cpp b/libs/meter/meter_types/test/test_dist_summary.cpp index bd4627f..7e15d57 100644 --- a/libs/meter/meter_types/test/test_dist_summary.cpp +++ b/libs/meter/meter_types/test/test_dist_summary.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/libs/meter/meter_types/test/test_gauge.cpp b/libs/meter/meter_types/test/test_gauge.cpp index eb3ef5a..39362ec 100644 --- a/libs/meter/meter_types/test/test_gauge.cpp +++ b/libs/meter/meter_types/test/test_gauge.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/libs/meter/meter_types/test/test_max_gauge.cpp b/libs/meter/meter_types/test/test_max_gauge.cpp index 2a7aa93..0052f06 100644 --- a/libs/meter/meter_types/test/test_max_gauge.cpp +++ b/libs/meter/meter_types/test/test_max_gauge.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/libs/meter/meter_types/test/test_monotonic_counter.cpp b/libs/meter/meter_types/test/test_monotonic_counter.cpp index 168c972..3a9952b 100644 --- a/libs/meter/meter_types/test/test_monotonic_counter.cpp +++ b/libs/meter/meter_types/test/test_monotonic_counter.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp index badf481..b3cfa7e 100644 --- a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp +++ b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp index f727e11..42e0e38 100644 --- a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp +++ b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/libs/meter/meter_types/test/test_percentile_timer.cpp b/libs/meter/meter_types/test/test_percentile_timer.cpp index 5eda430..4fd9d43 100644 --- a/libs/meter/meter_types/test/test_percentile_timer.cpp +++ b/libs/meter/meter_types/test/test_percentile_timer.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/libs/meter/meter_types/test/test_timer.cpp b/libs/meter/meter_types/test/test_timer.cpp index 5c6bbd7..4b0cfbf 100644 --- a/libs/meter/meter_types/test/test_timer.cpp +++ b/libs/meter/meter_types/test/test_timer.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include diff --git a/libs/writer/writer_wrapper/CMakeLists.txt b/libs/writer/writer_wrapper/CMakeLists.txt index 5267439..45c3f3a 100644 --- a/libs/writer/writer_wrapper/CMakeLists.txt +++ b/libs/writer/writer_wrapper/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(spectator-writer-wrapper - src/Writer.cpp + writer.cpp ) target_link_libraries(spectator-writer-wrapper diff --git a/libs/writer/writer_wrapper/src/Writer.cpp b/libs/writer/writer_wrapper/writer.cpp similarity index 97% rename from libs/writer/writer_wrapper/src/Writer.cpp rename to libs/writer/writer_wrapper/writer.cpp index 669481d..292ef24 100644 --- a/libs/writer/writer_wrapper/src/Writer.cpp +++ b/libs/writer/writer_wrapper/writer.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/libs/writer/writer_wrapper/include/Writer.h b/libs/writer/writer_wrapper/writer.h similarity index 100% rename from libs/writer/writer_wrapper/include/Writer.h rename to libs/writer/writer_wrapper/writer.h diff --git a/libs/writer/writer_wrapper/include/writer_test_helper.h b/libs/writer/writer_wrapper/writer_test_helper.h similarity index 92% rename from libs/writer/writer_wrapper/include/writer_test_helper.h rename to libs/writer/writer_wrapper/writer_test_helper.h index aaa5ef9..bc9b2a5 100644 --- a/libs/writer/writer_wrapper/include/writer_test_helper.h +++ b/libs/writer/writer_wrapper/writer_test_helper.h @@ -1,6 +1,6 @@ #pragma once -#include +#include /** * WriterTestHelper - A utility class to help with testing Writer functionality diff --git a/spectator/CMakeLists.txt b/spectator/CMakeLists.txt index 40e14d2..c9ca3e6 100644 --- a/spectator/CMakeLists.txt +++ b/spectator/CMakeLists.txt @@ -1,5 +1,5 @@ add_library(registry - src/registry.cpp + registry.cpp ) target_include_directories(registry PUBLIC @@ -14,7 +14,7 @@ target_link_libraries(registry spectator-writer-wrapper ) -add_executable(registry-test test/test_registry.cpp) +add_executable(registry-test test_registry.cpp) target_link_libraries(registry-test PRIVATE GTest::gtest GTest::gtest_main diff --git a/spectator/src/registry.cpp b/spectator/registry.cpp similarity index 98% rename from spectator/src/registry.cpp rename to spectator/registry.cpp index 99743f4..a0bcfc0 100644 --- a/spectator/src/registry.cpp +++ b/spectator/registry.cpp @@ -1,4 +1,4 @@ -#include +#include Registry::Registry(const Config& config) : m_config(config) { Writer::Initialize(config.GetWriterType()); } diff --git a/spectator/include/registry.h b/spectator/registry.h similarity index 97% rename from spectator/include/registry.h rename to spectator/registry.h index adbb490..d9585e6 100644 --- a/spectator/include/registry.h +++ b/spectator/registry.h @@ -3,7 +3,7 @@ #include #include #include -#include // Include Writer.h +#include #include #include diff --git a/spectator/test/test_registry.cpp b/spectator/test_registry.cpp similarity index 99% rename from spectator/test/test_registry.cpp rename to spectator/test_registry.cpp index eb288c4..7882332 100644 --- a/spectator/test/test_registry.cpp +++ b/spectator/test_registry.cpp @@ -1,8 +1,8 @@ #include #include -#include "../include/registry.h" -#include +#include +#include #include From a20e641c8820a5ac2111a214f215153d9b55dfec Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Mon, 16 Jun 2025 14:13:32 -0500 Subject: [PATCH 12/34] Add buffering --- .../meter/meter_types/test/test_age_gauge.cpp | 4 +- libs/meter/meter_types/test/test_counter.cpp | 4 +- .../meter_types/test/test_dist_summary.cpp | 4 +- libs/meter/meter_types/test/test_gauge.cpp | 4 +- .../meter/meter_types/test/test_max_gauge.cpp | 2 +- .../test/test_monotonic_counter.cpp | 4 +- .../test/test_monotonic_counter_uint.cpp | 4 +- .../test/test_percentile_dist_summary.cpp | 4 +- .../test/test_percentile_timer.cpp | 4 +- libs/meter/meter_types/test/test_timer.cpp | 4 +- .../writer_config/test_writer_config.cpp | 20 +-- libs/writer/writer_config/writer_config.cpp | 8 ++ libs/writer/writer_config/writer_config.h | 6 +- .../writer_types/test/test_uds_writer.cpp | 2 +- .../test_utils/uds_server/uds_server.cpp | 20 ++- libs/writer/writer_wrapper/CMakeLists.txt | 15 ++- libs/writer/writer_wrapper/test_writer.cpp | 126 ++++++++++++++++++ libs/writer/writer_wrapper/writer.cpp | 122 +++++++++++++++-- libs/writer/writer_wrapper/writer.h | 35 +++-- .../writer_wrapper/writer_test_helper.h | 4 +- spectator/test_registry.cpp | 56 ++++---- 21 files changed, 366 insertions(+), 86 deletions(-) create mode 100644 libs/writer/writer_wrapper/test_writer.cpp diff --git a/libs/meter/meter_types/test/test_age_gauge.cpp b/libs/meter/meter_types/test/test_age_gauge.cpp index 3be0eea..095bbf2 100644 --- a/libs/meter/meter_types/test/test_age_gauge.cpp +++ b/libs/meter/meter_types/test/test_age_gauge.cpp @@ -16,7 +16,7 @@ TEST_F(AgeGaugeTest, Now) AgeGauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Now(); - EXPECT_EQ("A:age_gauge:0", writer->LastLine()); + EXPECT_EQ("A:age_gauge:0\n", writer->LastLine()); } TEST_F(AgeGaugeTest, Set) @@ -26,5 +26,5 @@ TEST_F(AgeGaugeTest, Set) AgeGauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Set(10); - EXPECT_EQ("A:age_gauge:10", writer->LastLine()); + EXPECT_EQ("A:age_gauge:10\n", writer->LastLine()); } \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_counter.cpp b/libs/meter/meter_types/test/test_counter.cpp index dcccb69..dbc4129 100644 --- a/libs/meter/meter_types/test/test_counter.cpp +++ b/libs/meter/meter_types/test/test_counter.cpp @@ -17,9 +17,9 @@ TEST_F(CounterTest, increment) Counter c(tid); EXPECT_TRUE(writer->IsEmpty()); c.Increment(); - EXPECT_EQ("c:counter:1.000000", writer->LastLine()); + EXPECT_EQ("c:counter:1.000000\n", writer->LastLine()); c.Increment(2); - EXPECT_EQ("c:counter:2.000000", writer->LastLine()); + EXPECT_EQ("c:counter:2.000000\n", writer->LastLine()); } TEST_F(CounterTest, incrementNegative) diff --git a/libs/meter/meter_types/test/test_dist_summary.cpp b/libs/meter/meter_types/test/test_dist_summary.cpp index 7e15d57..312b262 100644 --- a/libs/meter/meter_types/test/test_dist_summary.cpp +++ b/libs/meter/meter_types/test/test_dist_summary.cpp @@ -17,7 +17,7 @@ TEST_F(DistSummaryTest, record) EXPECT_TRUE(writer->IsEmpty()); ds.Record(42); - EXPECT_EQ("d:dist_summary:42", writer->LastLine()); + EXPECT_EQ("d:dist_summary:42\n", writer->LastLine()); } TEST_F(DistSummaryTest, recordNegative) @@ -39,5 +39,5 @@ TEST_F(DistSummaryTest, recordZero) EXPECT_TRUE(writer->IsEmpty()); ds.Record(0); - EXPECT_EQ("d:dist_summary:0", writer->LastLine()); + EXPECT_EQ("d:dist_summary:0\n", writer->LastLine()); } \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_gauge.cpp b/libs/meter/meter_types/test/test_gauge.cpp index 39362ec..466fe07 100644 --- a/libs/meter/meter_types/test/test_gauge.cpp +++ b/libs/meter/meter_types/test/test_gauge.cpp @@ -16,7 +16,7 @@ TEST_F(GaugeTest, Now) Gauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Set(1); - EXPECT_EQ("g:gauge:1.000000", writer->LastLine()); + EXPECT_EQ("g:gauge:1.000000\n", writer->LastLine()); } TEST_F(GaugeTest, TTL) @@ -26,5 +26,5 @@ TEST_F(GaugeTest, TTL) Gauge g(tid, 10); EXPECT_TRUE(writer->IsEmpty()); g.Set(42); - EXPECT_EQ("g,10:gauge:42.000000", writer->LastLine()); + EXPECT_EQ("g,10:gauge:42.000000\n", writer->LastLine()); } \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_max_gauge.cpp b/libs/meter/meter_types/test/test_max_gauge.cpp index 0052f06..573bcd6 100644 --- a/libs/meter/meter_types/test/test_max_gauge.cpp +++ b/libs/meter/meter_types/test/test_max_gauge.cpp @@ -16,5 +16,5 @@ TEST_F(MaxGaugeTest, Set) MaxGauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Set(0); - EXPECT_EQ("m:max_gauge:0.000000", writer->LastLine()); + EXPECT_EQ("m:max_gauge:0.000000\n", writer->LastLine()); } \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_monotonic_counter.cpp b/libs/meter/meter_types/test/test_monotonic_counter.cpp index 3a9952b..7bed63a 100644 --- a/libs/meter/meter_types/test/test_monotonic_counter.cpp +++ b/libs/meter/meter_types/test/test_monotonic_counter.cpp @@ -16,7 +16,7 @@ TEST_F(MonotonicCounterTest, SetValue) MonotonicCounter mc(tid); EXPECT_TRUE(writer->IsEmpty()); mc.Set(1); - EXPECT_EQ("C:monotonic_counter:1.000000", writer->LastLine()); + EXPECT_EQ("C:monotonic_counter:1.000000\n", writer->LastLine()); } TEST_F(MonotonicCounterTest, SetNegativeValue) @@ -26,5 +26,5 @@ TEST_F(MonotonicCounterTest, SetNegativeValue) MonotonicCounter mc(tid); EXPECT_TRUE(writer->IsEmpty()); mc.Set(-1); - EXPECT_EQ("C:monotonic_counter:-1.000000", writer->LastLine()); + EXPECT_EQ("C:monotonic_counter:-1.000000\n", writer->LastLine()); } \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp index b3cfa7e..94aef7a 100644 --- a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp +++ b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp @@ -17,7 +17,7 @@ TEST_F(MonoCounterTest, set) EXPECT_TRUE(writer->IsEmpty()); mc.Set(1); - EXPECT_EQ("U:monotonic_counter_uint:1", writer->LastLine()); + EXPECT_EQ("U:monotonic_counter_uint:1\n", writer->LastLine()); } TEST_F(MonoCounterTest, setNegative) @@ -28,5 +28,5 @@ TEST_F(MonoCounterTest, setNegative) EXPECT_TRUE(writer->IsEmpty()); mc.Set(-1); - EXPECT_EQ("U:monotonic_counter_uint:18446744073709551615", writer->LastLine()); + EXPECT_EQ("U:monotonic_counter_uint:18446744073709551615\n", writer->LastLine()); } \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp index 42e0e38..e691a6f 100644 --- a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp +++ b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp @@ -17,7 +17,7 @@ TEST_F(PercentileDistSummaryTest, record) EXPECT_TRUE(writer->IsEmpty()); pds.Record(42); - EXPECT_EQ("D:percentile_dist_summary:42", writer->LastLine()); + EXPECT_EQ("D:percentile_dist_summary:42\n", writer->LastLine()); } TEST_F(PercentileDistSummaryTest, recordNegative) @@ -39,5 +39,5 @@ TEST_F(PercentileDistSummaryTest, recordZero) EXPECT_TRUE(writer->IsEmpty()); pds.Record(0); - EXPECT_EQ("D:percentile_dist_summary:0", writer->LastLine()); + EXPECT_EQ("D:percentile_dist_summary:0\n", writer->LastLine()); } \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_percentile_timer.cpp b/libs/meter/meter_types/test/test_percentile_timer.cpp index 4fd9d43..1d1f8ef 100644 --- a/libs/meter/meter_types/test/test_percentile_timer.cpp +++ b/libs/meter/meter_types/test/test_percentile_timer.cpp @@ -17,7 +17,7 @@ TEST_F(PercentileTimerTest, record) EXPECT_TRUE(writer->IsEmpty()); pt.Record(42); - EXPECT_EQ("T:percentile_timer:42.000000", writer->LastLine()); + EXPECT_EQ("T:percentile_timer:42.000000\n", writer->LastLine()); } TEST_F(PercentileTimerTest, recordNegative) @@ -39,5 +39,5 @@ TEST_F(PercentileTimerTest, recordZero) EXPECT_TRUE(writer->IsEmpty()); pt.Record(0); - EXPECT_EQ("T:percentile_timer:0.000000", writer->LastLine()); + EXPECT_EQ("T:percentile_timer:0.000000\n", writer->LastLine()); } \ No newline at end of file diff --git a/libs/meter/meter_types/test/test_timer.cpp b/libs/meter/meter_types/test/test_timer.cpp index 4b0cfbf..12aeced 100644 --- a/libs/meter/meter_types/test/test_timer.cpp +++ b/libs/meter/meter_types/test/test_timer.cpp @@ -17,7 +17,7 @@ TEST_F(TimerTest, record) EXPECT_TRUE(writer->IsEmpty()); t.Record(42); - EXPECT_EQ("t:timer:42.000000", writer->LastLine()); + EXPECT_EQ("t:timer:42.000000\n", writer->LastLine()); } TEST_F(TimerTest, recordNegative) @@ -39,5 +39,5 @@ TEST_F(TimerTest, recordZero) EXPECT_TRUE(writer->IsEmpty()); t.Record(0); - EXPECT_EQ("t:timer:0.000000", writer->LastLine()); + EXPECT_EQ("t:timer:0.000000\n", writer->LastLine()); } \ No newline at end of file diff --git a/libs/writer/writer_config/test_writer_config.cpp b/libs/writer/writer_config/test_writer_config.cpp index 8cd75ef..617a9cc 100644 --- a/libs/writer/writer_config/test_writer_config.cpp +++ b/libs/writer/writer_config/test_writer_config.cpp @@ -90,21 +90,13 @@ TEST_F(WriterConfigTest, URLBasedWriterTypes) } } -TEST_F(WriterConfigTest, EnvironmentVariableOverride) +TEST_F(WriterConfigTest, BufferingConstructor) { - { - envGuard.setValue(WriterTypes::Memory); - WriterConfig config(WriterTypes::UDP); // This should be ignored due to env var - EXPECT_EQ(config.GetType(), WriterType::Memory); - EXPECT_EQ(config.GetLocation(), DefaultLocations::NoLocation); - } - - { - envGuard.unsetValue(); - WriterConfig config(WriterTypes::Memory); - EXPECT_EQ(config.GetType(), WriterType::Memory); - EXPECT_EQ(config.GetLocation(), DefaultLocations::NoLocation); - } + + WriterConfig config(WriterTypes::UDP, 2048); + EXPECT_EQ(config.GetType(), WriterType::UDP); + EXPECT_EQ(config.GetBufferSize(), 2048); + EXPECT_TRUE(config.IsBufferingEnabled()); } TEST_F(WriterConfigTest, InvalidWriterType) diff --git a/libs/writer/writer_config/writer_config.cpp b/libs/writer/writer_config/writer_config.cpp index 69441e4..2ac879d 100644 --- a/libs/writer/writer_config/writer_config.cpp +++ b/libs/writer/writer_config/writer_config.cpp @@ -46,4 +46,12 @@ WriterConfig::WriterConfig(const std::string& type) m_location = location; } Logger::debug("WriterConfig initialized with type: {}, location: {}", WriterTypeToString(m_type), m_location); +} + +WriterConfig::WriterConfig(const std::string& type, const unsigned int bufferSize) + : WriterConfig(type) // Constructor delegation +{ + m_bufferSize = bufferSize; + m_isBufferingEnabled = true; + Logger::debug("WriterConfig buffering enabled with size: {}", m_bufferSize); } \ No newline at end of file diff --git a/libs/writer/writer_config/writer_config.h b/libs/writer/writer_config/writer_config.h index 8fffd93..e5911cd 100644 --- a/libs/writer/writer_config/writer_config.h +++ b/libs/writer/writer_config/writer_config.h @@ -10,12 +10,16 @@ class WriterConfig { public: WriterConfig(const std::string& type); + WriterConfig(const std::string& type, const unsigned int bufferSize); const WriterType& GetType() const noexcept { return m_type; }; - + const unsigned int GetBufferSize() const noexcept { return m_bufferSize; }; + const bool IsBufferingEnabled() const noexcept { return m_isBufferingEnabled; }; const std::string& GetLocation() const noexcept { return m_location; }; private: WriterType m_type; std::string m_location; + unsigned int m_bufferSize; + bool m_isBufferingEnabled = false; }; \ No newline at end of file diff --git a/libs/writer/writer_types/test/test_uds_writer.cpp b/libs/writer/writer_types/test/test_uds_writer.cpp index b5c7dc7..9eb5318 100644 --- a/libs/writer/writer_types/test/test_uds_writer.cpp +++ b/libs/writer/writer_types/test/test_uds_writer.cpp @@ -101,7 +101,7 @@ TEST_F(UDSWriterTest, CloseAndReopen) writer2.Write(message2); // Wait for message processing - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + std::this_thread::sleep_for(std::chrono::milliseconds(300)); // Verify second message messages = get_uds_messages(); diff --git a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp index f33774b..898459d 100644 --- a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp +++ b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp @@ -88,15 +88,27 @@ try } } - // Connection accepted, set back to blocking for data reading - socket.non_blocking(false); + // Connection accepted, set to non-blocking to avoid hanging + socket.non_blocking(true); // Buffer for reading data std::array buffer; - while (true) + while (uds_server_running) { + // We need to handle both data availability and potential errors boost::system::error_code read_ec; - std::size_t bytes_read = socket.read_some(boost::asio::buffer(buffer), read_ec); + std::size_t bytes_read = 0; + + // Try to read data even if none is immediately available + // This allows us to detect connection closure properly + bytes_read = socket.read_some(boost::asio::buffer(buffer), read_ec); + + // Handle the case where no data is available + if (read_ec == boost::asio::error::would_block) { + // No data available, wait a bit and try again + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + continue; + } if (read_ec == boost::asio::error::eof) { diff --git a/libs/writer/writer_wrapper/CMakeLists.txt b/libs/writer/writer_wrapper/CMakeLists.txt index 45c3f3a..54fa682 100644 --- a/libs/writer/writer_wrapper/CMakeLists.txt +++ b/libs/writer/writer_wrapper/CMakeLists.txt @@ -6,4 +6,17 @@ target_link_libraries(spectator-writer-wrapper PUBLIC spectator-logger spectator-writer-types -) \ No newline at end of file +) + +add_executable(writer_test + test_writer.cpp +) + +target_link_libraries(writer_test + PRIVATE + GTest::GTest + GTest::Main + spectator-writer-wrapper + uds_server_lib +) +add_test(NAME writer_test COMMAND writer_test) \ No newline at end of file diff --git a/libs/writer/writer_wrapper/test_writer.cpp b/libs/writer/writer_wrapper/test_writer.cpp new file mode 100644 index 0000000..f2f7794 --- /dev/null +++ b/libs/writer/writer_wrapper/test_writer.cpp @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../writer_types/test_utils/uds_server/uds_server.h" + +// Test fixture for UDS Writer tests +class WriterWrapperUDSWriterTest : public ::testing::Test +{ + protected: + void SetUp() override + { + // Set the server to run + uds_server_running = true; + + // Clear any existing messages from previous tests + clear_uds_messages(); + + // Start the UDS server in a separate thread + server_thread = std::thread( + []() + { + // This calls our server function directly + listen_for_uds_messages(); + }); + + // Give the server time to start + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } + + void TearDown() override + { + // Signal the server to stop + uds_server_running = false; + + // Terminate the server thread + if (server_thread.joinable()) + { + server_thread.join(); + } + } + + std::thread server_thread; +}; + +TEST_F(WriterWrapperUDSWriterTest, MultithreadedWrite) +{ + Logger::info("Starting multithreaded write test..."); + + // Create a UDS writer with a small buffer size + const std::string unixUrl = "/tmp/test_uds_socket"; + WriterTestHelper::InitializeWriter(WriterType::Unix, unixUrl, 0, 30); + + // Number of threads and counters to create + const int numThreads = 4; + const int countersPerThread = 3; + const int incrementsPerCounter = 5; + + // Function for worker threads + auto worker = [&](int threadId) + { + // Create several counters per thread with unique names + for (int i = 0; i < countersPerThread; i++) + { + std::string counterName = std::format("counter.thread{}.{}", threadId, i); + MeterId meterId(counterName); + Counter counter(meterId); + + // Increment each counter multiple times + for (int j = 0; j < incrementsPerCounter; j++) + { + counter.Increment(); + } + } + }; + + // Start worker threads + std::vector threads; + for (int i = 0; i < numThreads; i++) + { + threads.emplace_back(worker, i); + } + + // Wait for all threads to complete + for (auto& t : threads) + { + t.join(); + } + + // Give some time for messages to be sent + std::this_thread::sleep_for(std::chrono::milliseconds(900)); + + // Check messages + auto msgs = get_uds_messages(); + EXPECT_FALSE(msgs.empty()); + + // Verify total number of increments + int expectedIncrements = numThreads * countersPerThread * incrementsPerCounter; + int actualIncrements = 0; + + // Verify every string in msgs follows the form counter.thread. + std::regex counter_regex(R"(c:counter\.thread\d+\.\d+:1.000000)"); + for (const auto& msg : msgs) + { + std::stringstream ss(msg); + std::string line; + while (std::getline(ss, line)) + { + if (!line.empty()) + { + EXPECT_TRUE(std::regex_match(line, counter_regex)) << "Unexpected counter format: " << line; + actualIncrements++; + } + } + } + + EXPECT_EQ(actualIncrements, expectedIncrements); +} \ No newline at end of file diff --git a/libs/writer/writer_wrapper/writer.cpp b/libs/writer/writer_wrapper/writer.cpp index 292ef24..d09d7f0 100644 --- a/libs/writer/writer_wrapper/writer.cpp +++ b/libs/writer/writer_wrapper/writer.cpp @@ -4,12 +4,24 @@ #include #include +static const char NEW_LINE = '\n'; + Writer::~Writer() { - // No need to explicitly close here as unique_ptr will clean up + auto& instance = GetInstance(); + + if (instance.bufferingEnabled) + { + instance.shutdown.store(true); + instance.cv_receiver.notify_all(); + instance.cv_sender.notify_all(); + if (instance.sendingThread.joinable()) { + instance.sendingThread.join(); + } + } } -void Writer::Initialize(WriterType type, const std::string& param, int port) +void Writer::Initialize(WriterType type, const std::string& param, int port, unsigned int bufferSize) { // Get the singleton instance directly auto& instance = GetInstance(); @@ -36,6 +48,21 @@ void Writer::Initialize(WriterType type, const std::string& param, int port) } instance.m_currentType = type; + + if (bufferSize > 0) + { + instance.bufferingEnabled = true; + instance.bufferSize = bufferSize; + instance.buffer.reserve(bufferSize); + instance.writeImpl = &Writer::BufferedWrite; + // Create a thread with proper binding to the instance method + instance.sendingThread = std::thread(&Writer::ThreadSend, &instance); + } + else + { + // Explicitly set to non-buffered if buffer size is 0 + instance.writeImpl = &Writer::NonBufferedWrite; + } } catch (const std::exception& e) { @@ -64,24 +91,105 @@ void Writer::Reset() Logger::info("Writer has been reset"); } -void Writer::Write(const std::string& message) + +void Writer::TryToSend(const std::string& message) { auto& instance = GetInstance(); if (!instance.m_impl) { - Logger::error("Attempted to write with uninitialized writer implementation"); + Logger::error("Attempted to send with uninitialized writer implementation"); return; } try { instance.m_impl->Write(message); + Logger::debug("Message sent successfully: {}", message); } catch (const std::exception& e) { - Logger::error("Write operation failed: {}", e.what()); + Logger::error("Failed to send message: {}", e.what()); + } +} + +void Writer::ThreadSend() +{ + auto& instance = GetInstance(); + std::string message{}; + while (instance.shutdown.load() == false) + { + { + std::unique_lock lock(instance.writeMutex); + instance.cv_sender.wait( + lock, [&instance] { return instance.buffer.size() > instance.bufferSize || instance.shutdown.load(); }); + if (instance.shutdown.load() == true) + { + return; + } + message = std::move(instance.buffer); + instance.buffer = std::string(); + instance.buffer.reserve(instance.bufferSize); + } + instance.cv_receiver.notify_one(); + instance.TryToSend(message); + } +} + +void Writer::BufferedWrite(const std::string& message) +{ + auto& instance = GetInstance(); + + if (!instance.m_impl) + { + Logger::error("Attempted to write with uninitialized writer implementation"); + return; + } + + unsigned int currentBufferSize = instance.buffer.size(); + { + std::unique_lock lock(instance.writeMutex); + // TODO: Optimize memory alloc to not exceed allocated size + instance.cv_receiver.wait( + lock, [&instance] { return instance.buffer.size() < instance.bufferSize || instance.shutdown.load(); }); + if (instance.shutdown.load()) + { + Logger::warn("Write operation aborted due to shutdown signal"); + return; + } + instance.buffer.append(message); + instance.buffer.push_back(NEW_LINE); } + instance.buffer.size() > instance.bufferSize ? instance.cv_sender.notify_one() : instance.cv_receiver.notify_one(); +} + +void Writer::NonBufferedWrite(const std::string& message) +{ + // Since this is a non-static method, we're already operating on an instance + // and can call the instance method directly + this->TryToSend(message + NEW_LINE); +} + +void Writer::Write(const std::string& message) +{ + auto& instance = GetInstance(); + + if (!instance.m_impl) + { + Logger::error("Attempted to write with uninitialized writer implementation"); + return; + } + + try + { + // Call the member function using the pointer-to-member syntax + (instance.*(instance.writeImpl))(message); + Logger::debug("Message written successfully: {}", message); + } + catch (const std::exception& e) + { + Logger::error("Failed to write message: {}", e.what()); + } } void Writer::Close() @@ -103,6 +211,4 @@ void Writer::Close() { Logger::error("Failed to close writer: {}", e.what()); } -} - -WriterType Writer::GetWriterType() { return GetInstance().m_currentType; } +} \ No newline at end of file diff --git a/libs/writer/writer_wrapper/writer.h b/libs/writer/writer_wrapper/writer.h index fb4c8a8..d849968 100644 --- a/libs/writer/writer_wrapper/writer.h +++ b/libs/writer/writer_wrapper/writer.h @@ -29,23 +29,42 @@ class Writer final : public Singleton // Private constructor - enforces singleton pattern Writer() = default; - static void Initialize(WriterType type, const std::string& param = "", int port = 0); + static void Initialize(WriterType type, const std::string& param = "", int port = 0, unsigned int bufferSize = 0); static void Write(const std::string& message); - static void Close(); + void BufferedWrite(const std::string& message); - static WriterType GetWriterType(); + void NonBufferedWrite(const std::string& message); + + void ThreadSend(); + + void TryToSend(const std::string& message); + + void Close(); // Get the Writer's implementation for testing purposes static BaseWriter* GetImpl() { return Writer::GetInstance().m_impl.get(); } - /** - * Reset the writer to uninitialized state - * This method is private and can only be called by Registry - */ + static WriterType GetWriterType() { return GetInstance().m_currentType; } + + static void Reset(); - // Implementation details std::unique_ptr m_impl; WriterType m_currentType = WriterType::Memory; // Default type + bool bufferingEnabled = false; + unsigned int bufferSize = 0; + std::string buffer{}; + + // Function pointer for write strategy - member function pointer + using WriteFunction = void (Writer::*)(const std::string&); + WriteFunction writeImpl = &Writer::NonBufferedWrite; // Default to non-buffered + + + // multithreading writes + std::mutex writeMutex; + std::thread sendingThread; + std::condition_variable cv_receiver; + std::condition_variable cv_sender; + std::atomic shutdown{false}; }; \ No newline at end of file diff --git a/libs/writer/writer_wrapper/writer_test_helper.h b/libs/writer/writer_wrapper/writer_test_helper.h index bc9b2a5..0b1b08c 100644 --- a/libs/writer/writer_wrapper/writer_test_helper.h +++ b/libs/writer/writer_wrapper/writer_test_helper.h @@ -12,9 +12,9 @@ class WriterTestHelper { public: // Initialize the Writer for testing purposes - static void InitializeWriter(WriterType type, const std::string& param = "", int port = 0) + static void InitializeWriter(WriterType type, const std::string& param = "", int port = 0, unsigned int bufferSize = 0) { - Writer::Initialize(type, param, port); + Writer::Initialize(type, param, port, bufferSize); } // Reset the Writer for testing purposes diff --git a/spectator/test_registry.cpp b/spectator/test_registry.cpp index 7882332..d85a6dc 100644 --- a/spectator/test_registry.cpp +++ b/spectator/test_registry.cpp @@ -14,7 +14,7 @@ TEST(RegistryTest, Close) c.Increment(); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - EXPECT_EQ("c:counter:1.000000", memoryWriter->LastLine()); + EXPECT_EQ("c:counter:1.000000\n", memoryWriter->LastLine()); memoryWriter->Close(); EXPECT_TRUE(memoryWriter->IsEmpty()); @@ -31,10 +31,10 @@ TEST(RegistryTest, AgeGauge) EXPECT_TRUE(memoryWriter->IsEmpty()); g1.Set(1); - EXPECT_EQ("A:age_gauge:1", memoryWriter->LastLine()); + EXPECT_EQ("A:age_gauge:1\n", memoryWriter->LastLine()); g2.Set(2); - EXPECT_EQ("A:age_gauge,my-tags=bar:2", memoryWriter->LastLine()); + EXPECT_EQ("A:age_gauge,my-tags=bar:2\n", memoryWriter->LastLine()); } TEST(RegistryTest, AgeGaugeWithId) @@ -47,7 +47,7 @@ TEST(RegistryTest, AgeGaugeWithId) EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(0); - EXPECT_EQ("A:age_gauge,extra-tags=foo,my-tags=bar:0", + EXPECT_EQ("A:age_gauge,extra-tags=foo,my-tags=bar:0\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } @@ -62,19 +62,19 @@ TEST(RegistryTest, Counter) EXPECT_TRUE(memoryWriter->IsEmpty()); c1.Increment(); - EXPECT_EQ("c:counter:1.000000", memoryWriter->LastLine()); + EXPECT_EQ("c:counter:1.000000\n", memoryWriter->LastLine()); c2.Increment(); - EXPECT_EQ("c:counter,my-tags=bar:1.000000", memoryWriter->LastLine()); + EXPECT_EQ("c:counter,my-tags=bar:1.000000\n", memoryWriter->LastLine()); c1.Increment(2); - EXPECT_EQ("c:counter:2.000000", memoryWriter->LastLine()); + EXPECT_EQ("c:counter:2.000000\n", memoryWriter->LastLine()); c2.Increment(2); - EXPECT_EQ("c:counter,my-tags=bar:2.000000", memoryWriter->LastLine()); + EXPECT_EQ("c:counter,my-tags=bar:2.000000\n", memoryWriter->LastLine()); r.counter("counter").Increment(3); - EXPECT_EQ("c:counter:3.000000", memoryWriter->LastLine()); + EXPECT_EQ("c:counter:3.000000\n", memoryWriter->LastLine()); } TEST(RegistryTest, CounterWithId) @@ -87,15 +87,15 @@ TEST(RegistryTest, CounterWithId) EXPECT_TRUE(memoryWriter->IsEmpty()); c.Increment(); - EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:1.000000", + EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:1.000000\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); c.Increment(2); - EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:2.000000", + EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:2.000000\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); r.counter("counter", {{"my-tags", "bar"}}).Increment(3); - EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:3.000000", + EXPECT_EQ("c:counter,extra-tags=foo,my-tags=bar:3.000000\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } @@ -109,7 +109,7 @@ TEST(RegistryTest, DistributionSummary) EXPECT_TRUE(memoryWriter->IsEmpty()); d.Record(42); - EXPECT_EQ("d:distribution_summary:42", memoryWriter->LastLine()); + EXPECT_EQ("d:distribution_summary:42\n", memoryWriter->LastLine()); } TEST(RegistryTest, DistributionSummaryWithId) @@ -122,7 +122,7 @@ TEST(RegistryTest, DistributionSummaryWithId) EXPECT_TRUE(memoryWriter->IsEmpty()); d.Record(42); - EXPECT_EQ("d:distribution_summary,extra-tags=foo,my-tags=bar:42", + EXPECT_EQ("d:distribution_summary,extra-tags=foo,my-tags=bar:42\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } @@ -136,7 +136,7 @@ TEST(RegistryTest, Gauge) EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(42); - EXPECT_EQ("g:gauge:42.000000", memoryWriter->LastLine()); + EXPECT_EQ("g:gauge:42.000000\n", memoryWriter->LastLine()); } TEST(RegistryTest, GaugeWithId) @@ -149,7 +149,7 @@ TEST(RegistryTest, GaugeWithId) EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(42); - EXPECT_EQ("g:gauge,extra-tags=foo,my-tags=bar:42.000000", + EXPECT_EQ("g:gauge,extra-tags=foo,my-tags=bar:42.000000\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } @@ -188,7 +188,7 @@ TEST(RegistryTest, MaxGauge) EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(42); - EXPECT_EQ("m:max_gauge:42.000000", memoryWriter->LastLine()); + EXPECT_EQ("m:max_gauge:42.000000\n", memoryWriter->LastLine()); } TEST(RegistryTest, MaxGaugeWithId) @@ -201,7 +201,7 @@ TEST(RegistryTest, MaxGaugeWithId) EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(42); - EXPECT_EQ("m:max_gauge,extra-tags=foo,my-tags=bar:42.000000", + EXPECT_EQ("m:max_gauge,extra-tags=foo,my-tags=bar:42.000000\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } @@ -215,7 +215,7 @@ TEST(RegistryTest, MonotonicCounter) EXPECT_TRUE(memoryWriter->IsEmpty()); c.Set(42); - EXPECT_EQ("C:monotonic_counter:42.000000", memoryWriter->LastLine()); + EXPECT_EQ("C:monotonic_counter:42.000000\n", memoryWriter->LastLine()); } TEST(RegistryTest, MonotonicCounterWithId) @@ -228,7 +228,7 @@ TEST(RegistryTest, MonotonicCounterWithId) EXPECT_TRUE(memoryWriter->IsEmpty()); c.Set(42); - EXPECT_EQ("C:monotonic_counter,extra-tags=foo,my-tags=bar:42.000000", + EXPECT_EQ("C:monotonic_counter,extra-tags=foo,my-tags=bar:42.000000\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } @@ -242,7 +242,7 @@ TEST(RegistryTest, MonotonicCounterUint) EXPECT_TRUE(memoryWriter->IsEmpty()); c.Set(42); - EXPECT_EQ("U:monotonic_counter_uint:42", memoryWriter->LastLine()); + EXPECT_EQ("U:monotonic_counter_uint:42\n", memoryWriter->LastLine()); } TEST(RegistryTest, MonotonicCounterUintWithId) @@ -255,7 +255,7 @@ TEST(RegistryTest, MonotonicCounterUintWithId) EXPECT_TRUE(memoryWriter->IsEmpty()); c.Set(42); - EXPECT_EQ("U:monotonic_counter_uint,extra-tags=foo,my-tags=bar:42", + EXPECT_EQ("U:monotonic_counter_uint,extra-tags=foo,my-tags=bar:42\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } @@ -282,7 +282,7 @@ TEST(RegistryTest, PctDistributionSummary) EXPECT_TRUE(memoryWriter->IsEmpty()); d.Record(42); - EXPECT_EQ("D:pct_distribution_summary:42", memoryWriter->LastLine()); + EXPECT_EQ("D:pct_distribution_summary:42\n", memoryWriter->LastLine()); } TEST(RegistryTest, PctDistributionSummaryWithId) @@ -295,7 +295,7 @@ TEST(RegistryTest, PctDistributionSummaryWithId) EXPECT_TRUE(memoryWriter->IsEmpty()); d.Record(42); - EXPECT_EQ("D:pct_distribution_summary,extra-tags=foo,my-tags=bar:42", + EXPECT_EQ("D:pct_distribution_summary,extra-tags=foo,my-tags=bar:42\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } @@ -309,7 +309,7 @@ TEST(RegistryTest, PctTimer) EXPECT_TRUE(memoryWriter->IsEmpty()); t.Record(42); - EXPECT_EQ("T:pct_timer:42.000000", memoryWriter->LastLine()); + EXPECT_EQ("T:pct_timer:42.000000\n", memoryWriter->LastLine()); } TEST(RegistryTest, PctTimerWithId) @@ -322,7 +322,7 @@ TEST(RegistryTest, PctTimerWithId) EXPECT_TRUE(memoryWriter->IsEmpty()); t.Record(42); - EXPECT_EQ("T:pct_timer,extra-tags=foo,my-tags=bar:42.000000", + EXPECT_EQ("T:pct_timer,extra-tags=foo,my-tags=bar:42.000000\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } @@ -336,7 +336,7 @@ TEST(RegistryTest, Timer) EXPECT_TRUE(memoryWriter->IsEmpty()); t.Record(42); - EXPECT_EQ("t:timer:42.000000", memoryWriter->LastLine()); + EXPECT_EQ("t:timer:42.000000\n", memoryWriter->LastLine()); } TEST(RegistryTest, TimerWithId) @@ -349,6 +349,6 @@ TEST(RegistryTest, TimerWithId) EXPECT_TRUE(memoryWriter->IsEmpty()); t.Record(42); - EXPECT_EQ("t:timer,extra-tags=foo,my-tags=bar:42.000000", + EXPECT_EQ("t:timer,extra-tags=foo,my-tags=bar:42.000000\n", ParseProtocolLine(memoryWriter->LastLine()).value().to_string()); } \ No newline at end of file From 9e0e02ed7bc60a871518b13779ff16941e1f2218 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Tue, 17 Jun 2025 13:08:38 -0500 Subject: [PATCH 13/34] fix vexing error --- spectator/test_registry.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/spectator/test_registry.cpp b/spectator/test_registry.cpp index d85a6dc..315ddc5 100644 --- a/spectator/test_registry.cpp +++ b/spectator/test_registry.cpp @@ -8,7 +8,7 @@ TEST(RegistryTest, Close) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto c = r.counter("counter"); c.Increment(); @@ -22,7 +22,7 @@ TEST(RegistryTest, Close) TEST(RegistryTest, AgeGauge) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto g1 = r.age_gauge("age_gauge"); auto g2 = r.age_gauge("age_gauge", {{"my-tags", "bar"}}); @@ -53,7 +53,7 @@ TEST(RegistryTest, AgeGaugeWithId) TEST(RegistryTest, Counter) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto c1 = r.counter("counter"); auto c2 = r.counter("counter", {{"my-tags", "bar"}}); @@ -101,7 +101,7 @@ TEST(RegistryTest, CounterWithId) TEST(RegistryTest, DistributionSummary) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); @@ -128,7 +128,7 @@ TEST(RegistryTest, DistributionSummaryWithId) TEST(RegistryTest, Gauge) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); @@ -180,7 +180,7 @@ TEST(RegistryTest, GaugeWithIdWithTtlSeconds) TEST(RegistryTest, MaxGauge) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); @@ -207,7 +207,7 @@ TEST(RegistryTest, MaxGaugeWithId) TEST(RegistryTest, MonotonicCounter) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); @@ -234,7 +234,7 @@ TEST(RegistryTest, MonotonicCounterWithId) TEST(RegistryTest, MonotonicCounterUint) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); @@ -261,7 +261,7 @@ TEST(RegistryTest, MonotonicCounterUintWithId) TEST(RegistryTest, NewId) { - Config config1(WriterConfig(WriterTypes::Memory)); + auto config1 = Config(WriterConfig(WriterTypes::Memory)); auto r1 = Registry(config1); auto id1 = r1.new_id("id"); EXPECT_EQ("MeterId(name=id, tags={})", id1.to_string()); @@ -274,7 +274,7 @@ TEST(RegistryTest, NewId) TEST(RegistryTest, PctDistributionSummary) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); @@ -301,7 +301,7 @@ TEST(RegistryTest, PctDistributionSummaryWithId) TEST(RegistryTest, PctTimer) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); @@ -328,7 +328,7 @@ TEST(RegistryTest, PctTimerWithId) TEST(RegistryTest, Timer) { - Config config(WriterConfig(WriterTypes::Memory)); + auto config = Config(WriterConfig(WriterTypes::Memory)); auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); From 18baa1d9bc0ff20fd1d748dbe0b7b986dc112356 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Tue, 17 Jun 2025 14:59:50 -0500 Subject: [PATCH 14/34] resolve clion errors --- libs/config/config.cpp | 12 +++++------ libs/config/config.h | 3 --- libs/writer/writer_config/writer_config.cpp | 2 ++ libs/writer/writer_config/writer_config.h | 9 ++++----- .../writer/writer_types/src/memory_writer.cpp | 2 +- libs/writer/writer_wrapper/writer.cpp | 1 - spectator/registry.cpp | 20 +++++++++---------- spectator/registry.h | 20 +++++++++---------- 8 files changed, 33 insertions(+), 36 deletions(-) diff --git a/libs/config/config.cpp b/libs/config/config.cpp index 9c052fc..14af771 100644 --- a/libs/config/config.cpp +++ b/libs/config/config.cpp @@ -8,12 +8,7 @@ struct ConfigConstants static constexpr auto envVarProcess = "TITUS_PROCESS_NAME"; }; -Config::Config(const WriterConfig& writerConfig, const std::unordered_map& extraTags) - : m_extraTags(CalculateTags(extraTags)), m_writerConfig(writerConfig) -{ -} - -std::unordered_map Config::CalculateTags( +std::unordered_map CalculateTags( const std::unordered_map& tags) { std::unordered_map valid_tags; @@ -40,3 +35,8 @@ std::unordered_map Config::CalculateTags( return valid_tags; } + +Config::Config(const WriterConfig& writerConfig, const std::unordered_map& extraTags) + : m_extraTags(CalculateTags(extraTags)), m_writerConfig(writerConfig) +{ +} diff --git a/libs/config/config.h b/libs/config/config.h index 97a76af..5be25a5 100644 --- a/libs/config/config.h +++ b/libs/config/config.h @@ -22,9 +22,6 @@ class Config const WriterType& GetWriterType() const noexcept { return m_writerConfig.GetType(); } private: - std::unordered_map CalculateTags( - const std::unordered_map& tags); - std::unordered_map m_extraTags; WriterConfig m_writerConfig; }; \ No newline at end of file diff --git a/libs/writer/writer_config/writer_config.cpp b/libs/writer/writer_config/writer_config.cpp index 2ac879d..34906b3 100644 --- a/libs/writer/writer_config/writer_config.cpp +++ b/libs/writer/writer_config/writer_config.cpp @@ -1,5 +1,7 @@ #include +#include + struct WriterConfigConstants { static constexpr auto RuntimeErrorMessage = "Invalid writer type: "; diff --git a/libs/writer/writer_config/writer_config.h b/libs/writer/writer_config/writer_config.h index e5911cd..0640794 100644 --- a/libs/writer/writer_config/writer_config.h +++ b/libs/writer/writer_config/writer_config.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include @@ -12,10 +11,10 @@ class WriterConfig WriterConfig(const std::string& type); WriterConfig(const std::string& type, const unsigned int bufferSize); - const WriterType& GetType() const noexcept { return m_type; }; - const unsigned int GetBufferSize() const noexcept { return m_bufferSize; }; - const bool IsBufferingEnabled() const noexcept { return m_isBufferingEnabled; }; - const std::string& GetLocation() const noexcept { return m_location; }; + const WriterType& GetType() const noexcept { return m_type; } + const unsigned int GetBufferSize() const noexcept { return m_bufferSize; } + const bool IsBufferingEnabled() const noexcept { return m_isBufferingEnabled; } + const std::string& GetLocation() const noexcept { return m_location; } private: WriterType m_type; diff --git a/libs/writer/writer_types/src/memory_writer.cpp b/libs/writer/writer_types/src/memory_writer.cpp index 45a16f4..07e1f7c 100644 --- a/libs/writer/writer_types/src/memory_writer.cpp +++ b/libs/writer/writer_types/src/memory_writer.cpp @@ -22,7 +22,7 @@ void MemoryWriter::Clear() const std::string& MemoryWriter::LastLine() const noexcept { - static const std::string emptyString = ""; + static const std::string emptyString{}; if (true == m_messages.empty()) { diff --git a/libs/writer/writer_wrapper/writer.cpp b/libs/writer/writer_wrapper/writer.cpp index d09d7f0..c036869 100644 --- a/libs/writer/writer_wrapper/writer.cpp +++ b/libs/writer/writer_wrapper/writer.cpp @@ -146,7 +146,6 @@ void Writer::BufferedWrite(const std::string& message) return; } - unsigned int currentBufferSize = instance.buffer.size(); { std::unique_lock lock(instance.writeMutex); // TODO: Optimize memory alloc to not exceed allocated size diff --git a/spectator/registry.cpp b/spectator/registry.cpp index a0bcfc0..6bdaa75 100644 --- a/spectator/registry.cpp +++ b/spectator/registry.cpp @@ -22,14 +22,14 @@ MeterId Registry::new_id(const std::string& name, const std::unordered_map& tags) +AgeGauge Registry::age_gauge(const std::string& name, const std::unordered_map& tags) const { return AgeGauge(new_id(name, tags)); } AgeGauge Registry::age_gauge_with_id(const MeterId& meter_id) { return AgeGauge(meter_id); } -Counter Registry::counter(const std::string& name, const std::unordered_map& tags) +Counter Registry::counter(const std::string& name, const std::unordered_map& tags) const { return Counter(new_id(name, tags)); } @@ -37,7 +37,7 @@ Counter Registry::counter(const std::string& name, const std::unordered_map& tags) + const std::unordered_map& tags) const { return DistributionSummary(new_id(name, tags)); } @@ -48,7 +48,7 @@ DistributionSummary Registry::distribution_summary_with_id(const MeterId& meter_ } Gauge Registry::gauge(const std::string& name, const std::unordered_map& tags, - const std::optional& ttl_seconds) + const std::optional& ttl_seconds) const { return Gauge(new_id(name, tags), ttl_seconds); } @@ -58,7 +58,7 @@ Gauge Registry::gauge_with_id(const MeterId& meter_id, const std::optional& return Gauge(meter_id, ttl_seconds); } -MaxGauge Registry::max_gauge(const std::string& name, const std::unordered_map& tags) +MaxGauge Registry::max_gauge(const std::string& name, const std::unordered_map& tags) const { return MaxGauge(new_id(name, tags)); } @@ -66,7 +66,7 @@ MaxGauge Registry::max_gauge(const std::string& name, const std::unordered_map& tags) + const std::unordered_map& tags) const { return MonotonicCounter(new_id(name, tags)); } @@ -74,7 +74,7 @@ MonotonicCounter Registry::monotonic_counter(const std::string& name, MonotonicCounter Registry::monotonic_counter_with_id(const MeterId& meter_id) { return MonotonicCounter(meter_id); } MonotonicCounterUint Registry::monotonic_counter_uint(const std::string& name, - const std::unordered_map& tags) + const std::unordered_map& tags) const { return MonotonicCounterUint(new_id(name, tags)); } @@ -85,7 +85,7 @@ MonotonicCounterUint Registry::monotonic_counter_uint_with_id(const MeterId& met } PercentileDistributionSummary Registry::pct_distribution_summary( - const std::string& name, const std::unordered_map& tags) + const std::string& name, const std::unordered_map& tags) const { return PercentileDistributionSummary(new_id(name, tags)); } @@ -95,14 +95,14 @@ PercentileDistributionSummary Registry::pct_distribution_summary_with_id(const M return PercentileDistributionSummary(meter_id); } -PercentileTimer Registry::pct_timer(const std::string& name, const std::unordered_map& tags) +PercentileTimer Registry::pct_timer(const std::string& name, const std::unordered_map& tags) const { return PercentileTimer(new_id(name, tags)); } PercentileTimer Registry::pct_timer_with_id(const MeterId& meter_id) { return PercentileTimer(meter_id); } -Timer Registry::timer(const std::string& name, const std::unordered_map& tags) +Timer Registry::timer(const std::string& name, const std::unordered_map& tags) const { return Timer(new_id(name, tags)); } diff --git a/spectator/registry.h b/spectator/registry.h index d9585e6..874786f 100644 --- a/spectator/registry.h +++ b/spectator/registry.h @@ -21,58 +21,58 @@ class Registry MeterId new_id(const std::string& name, const std::unordered_map& tags = {}) const; AgeGauge age_gauge(const std::string& name, const std::unordered_map& tags = - std::unordered_map()); + std::unordered_map()) const; AgeGauge age_gauge_with_id(const MeterId& meter_id); Counter counter(const std::string& name, const std::unordered_map& tags = - std::unordered_map()); + std::unordered_map()) const; Counter counter_with_id(const MeterId& meter_id); DistributionSummary distribution_summary( const std::string& name, - const std::unordered_map& tags = std::unordered_map()); + const std::unordered_map& tags = std::unordered_map()) const; DistributionSummary distribution_summary_with_id(const MeterId& meter_id); Gauge gauge( const std::string& name, const std::unordered_map& tags = std::unordered_map(), - const std::optional& ttl_seconds = std::nullopt); + const std::optional& ttl_seconds = std::nullopt) const; Gauge gauge_with_id(const MeterId& meter_id, const std::optional& ttl_seconds = std::nullopt); MaxGauge max_gauge(const std::string& name, const std::unordered_map& tags = - std::unordered_map()); + std::unordered_map()) const; MaxGauge max_gauge_with_id(const MeterId& meter_id); MonotonicCounter monotonic_counter( const std::string& name, - const std::unordered_map& tags = std::unordered_map()); + const std::unordered_map& tags = std::unordered_map()) const; MonotonicCounter monotonic_counter_with_id(const MeterId& meter_id); MonotonicCounterUint monotonic_counter_uint( const std::string& name, - const std::unordered_map& tags = std::unordered_map()); + const std::unordered_map& tags = std::unordered_map()) const; MonotonicCounterUint monotonic_counter_uint_with_id(const MeterId& meter_id); PercentileDistributionSummary pct_distribution_summary( const std::string& name, - const std::unordered_map& tags = std::unordered_map()); + const std::unordered_map& tags = std::unordered_map()) const; PercentileDistributionSummary pct_distribution_summary_with_id(const MeterId& meter_id); PercentileTimer pct_timer(const std::string& name, const std::unordered_map& tags = - std::unordered_map()); + std::unordered_map()) const; PercentileTimer pct_timer_with_id(const MeterId& meter_id); Timer timer(const std::string& name, const std::unordered_map& tags = - std::unordered_map()); + std::unordered_map()) const; Timer timer_with_id(const MeterId& meter_id); From 46e7b91d209aa1608a9ee652e133b72e5d753fd2 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Tue, 17 Jun 2025 15:13:51 -0500 Subject: [PATCH 15/34] more clion fixes --- CMakeLists.txt | 1 - libs/README.md | 12 ++++++------ libs/config/README.md | 4 ++-- libs/meter/meter_id/meter_id.cpp | 4 ++-- spectator/registry.cpp | 5 +---- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 84a356f..a82ce1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,3 @@ -# filepath: /home/ebadeaux/Saturday/spec2-cpp/CMakeLists.txt cmake_minimum_required(VERSION 3.15) project(spectator-cpp VERSION 2.0 LANGUAGES CXX) diff --git a/libs/README.md b/libs/README.md index 478e9be..95ab922 100644 --- a/libs/README.md +++ b/libs/README.md @@ -4,13 +4,13 @@ This directory contains all the core libraries that make up the Spectator-CPP fr ## Library Overview -| Library | Description | -|---------|-------------| +| Library | Description | +|----------|----------------------------------------------------------------------------------------------| | `config` | Configuration handling for the Spectator Registry metrics including output location and tags | -| `logger` | Logging facilities used throughout the framework | -| `meter` | Core metrics implementations including counters, gauges, timers, and meter identification | -| `utils` | Utility classes and helpers including singleton patterns | -| `writer` | Output writers for metrics data (file, memory, UDP, Unix Domain Socket) | +| `logger` | Logging facilities used throughout the framework | +| `meter` | Core metrics implementations including counters, gauges, timers, and meter identification | +| `utils` | Utility classes and helpers including singleton patterns | +| `writer` | Output writers for metrics data (file, memory, UDP, Unix Domain Socket) | ## Usage diff --git a/libs/config/README.md b/libs/config/README.md index 5056e7f..d6e53255 100644 --- a/libs/config/README.md +++ b/libs/config/README.md @@ -4,7 +4,7 @@ The `Config` class serves as the configuration object for the Registry class, which manages how metrics are sent to SpectatorD. The `Config` constructor takes two parameters. The first parameter is required and is a `WriterConfig` object. This object defines -how metrics will be sent to `SpectatorD`. The second parameter `extraTags` is a unordered map of strings allowing you to provide additional tags to +how metrics will be sent to `SpectatorD`. The second parameter `extraTags` is an unordered map of strings allowing you to provide additional tags to all of your metrics. Extra tags are additional key-value pairs attached to all metrics and will be merged with environment-derived tags. ## Usage @@ -37,5 +37,5 @@ If the following environment variables are set and not empty, there key and valu ### Warning -If the environment variable `SPECTATOR_OUTPUT_LOCATION` is set this will override the value specefied in the `WriterConfig` +If the environment variable `SPECTATOR_OUTPUT_LOCATION` is set this will override the value specified in the `WriterConfig` read the `WriterConfig` readme.md for more details. \ No newline at end of file diff --git a/libs/meter/meter_id/meter_id.cpp b/libs/meter/meter_id/meter_id.cpp index 7006d87..24a830a 100644 --- a/libs/meter/meter_id/meter_id.cpp +++ b/libs/meter/meter_id/meter_id.cpp @@ -91,11 +91,11 @@ size_t std::hash::operator()(const MeterId& id) const for (const auto& tag : id.GetTags()) { // Combine key and value hashes - size_t pair_hash = std::hash{}(tag.first) ^ (std::hash{}(tag.second) << 1); + size_t pair_hash = std::hash{}(tag.first) ^ std::hash{}(tag.second) << 1; // Combine with the accumulated tags hash tags_hash ^= pair_hash + 0x9e3779b9 + (tags_hash << 6) + (tags_hash >> 2); } // Combine name hash and tags hash - return name_hash ^ (tags_hash << 1); + return name_hash ^ tags_hash << 1; } diff --git a/spectator/registry.cpp b/spectator/registry.cpp index 6bdaa75..5db9100 100644 --- a/spectator/registry.cpp +++ b/spectator/registry.cpp @@ -16,10 +16,7 @@ MeterId Registry::new_id(const std::string& name, const std::unordered_mapm_config.GetExtraTags()); - } + return new_meter_id.WithTags(this->m_config.GetExtraTags()); } AgeGauge Registry::age_gauge(const std::string& name, const std::unordered_map& tags) const From fd1652d877d5385df92e7a9f1b028740903ea6dc Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Wed, 18 Jun 2025 10:58:25 -0500 Subject: [PATCH 16/34] Clang Tidy improvements --- .gitignore | 2 ++ libs/config/test_config.cpp | 2 +- libs/meter/meter_id/meter_id.cpp | 6 +++--- libs/meter/meter_id/test_meter_id.cpp | 20 +++++++++---------- .../meter/meter_types/test/test_age_gauge.cpp | 6 +++--- libs/meter/meter_types/test/test_counter.cpp | 6 +++--- .../meter_types/test/test_dist_summary.cpp | 8 ++++---- libs/meter/meter_types/test/test_gauge.cpp | 6 +++--- .../meter/meter_types/test/test_max_gauge.cpp | 4 ++-- .../test/test_monotonic_counter.cpp | 6 +++--- .../test/test_monotonic_counter_uint.cpp | 6 +++--- .../test/test_percentile_dist_summary.cpp | 8 ++++---- .../test/test_percentile_timer.cpp | 8 ++++---- libs/meter/meter_types/test/test_timer.cpp | 8 ++++---- libs/utils/src/util.cpp | 2 +- .../writer_config/test_writer_config.cpp | 16 +++++++-------- libs/writer/writer_config/writer_config.cpp | 4 ++-- libs/writer/writer_config/writer_config.h | 6 +++--- libs/writer/writer_types/src/uds_writer.cpp | 2 +- .../writer_types/test/test_memory_writer.cpp | 2 +- .../writer_types/test/test_udp_writer.cpp | 11 +++++----- .../writer_types/test/test_uds_writer.cpp | 14 ++++++------- .../test_utils/udp_server/udp_server.cpp | 4 ++-- .../test_utils/uds_server/uds_server.cpp | 11 ++++------ libs/writer/writer_wrapper/test_writer.cpp | 2 +- libs/writer/writer_wrapper/writer.cpp | 4 ++-- 26 files changed, 87 insertions(+), 87 deletions(-) diff --git a/.gitignore b/.gitignore index b193668..656c726 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ .vscode/ CMakeUserPresets.json cmake-build/ +cmake-build-debug/ +cmake-build-release/ conan_provider.cmake spectator/valid_chars.inc venv/ \ No newline at end of file diff --git a/libs/config/test_config.cpp b/libs/config/test_config.cpp index 90010d5..a8f1c35 100644 --- a/libs/config/test_config.cpp +++ b/libs/config/test_config.cpp @@ -37,7 +37,7 @@ class EnvironmentVariableGuard std::optional m_originalValue; }; -class ConfigTest : public ::testing::Test +class ConfigTest : public testing::Test { protected: // Create guards for each environment variable diff --git a/libs/meter/meter_id/meter_id.cpp b/libs/meter/meter_id/meter_id.cpp index 24a830a..524021e 100644 --- a/libs/meter/meter_id/meter_id.cpp +++ b/libs/meter/meter_id/meter_id.cpp @@ -21,17 +21,17 @@ std::unordered_map ValidateTags(const std::unordered_m return validTags; } -std::string RepleaceInvalidChars(const std::string& s) { return std::regex_replace(s, INVALID_CHARS, "_"); } +std::string ReplaceInvalidChars(const std::string& s) { return std::regex_replace(s, INVALID_CHARS, "_"); } std::string ToSpectatorId(const std::string& name, const std::unordered_map& tags) { std::ostringstream ss; - ss << RepleaceInvalidChars(name); + ss << ReplaceInvalidChars(name); if (!tags.empty()) { for (const auto& tag : tags) { - ss << "," << RepleaceInvalidChars(tag.first) << "=" << RepleaceInvalidChars(tag.second); + ss << "," << ReplaceInvalidChars(tag.first) << "=" << ReplaceInvalidChars(tag.second); } } return ss.str(); diff --git a/libs/meter/meter_id/test_meter_id.cpp b/libs/meter/meter_id/test_meter_id.cpp index 31820f9..b5dde3f 100644 --- a/libs/meter/meter_id/test_meter_id.cpp +++ b/libs/meter/meter_id/test_meter_id.cpp @@ -4,35 +4,35 @@ TEST(MeterIdTest, EqualsSameName) { - MeterId id1("foo"); - MeterId id2("foo"); + const MeterId id1("foo"); + const MeterId id2("foo"); EXPECT_EQ(id1, id2); } TEST(MeterIdTest, EqualsSameTags) { - MeterId id1("foo", {{"a", "1"}, {"b", "2"}, {"c", "3"}}); - MeterId id2("foo", {{"c", "3"}, {"b", "2"}, {"a", "1"}}); + const MeterId id1("foo", {{"a", "1"}, {"b", "2"}, {"c", "3"}}); + const MeterId id2("foo", {{"c", "3"}, {"b", "2"}, {"a", "1"}}); EXPECT_EQ(id1, id2); } TEST(MeterIdTest, HashSameTags) { - MeterId id1("foo", {{"a", "1"}, {"b", "2"}, {"c", "3"}}); - MeterId id2("foo", {{"c", "3"}, {"b", "2"}, {"a", "1"}}); + const MeterId id1("foo", {{"a", "1"}, {"b", "2"}, {"c", "3"}}); + const MeterId id2("foo", {{"c", "3"}, {"b", "2"}, {"a", "1"}}); EXPECT_EQ(std::hash{}(id1), std::hash{}(id2)); } TEST(MeterIdTest, IllegalCharsAreReplaced) { - MeterId id("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo"); + const MeterId id("test`!@#$%^&*()-=~_+[]{}\\|;:'\",<.>/?foo"); EXPECT_EQ("test______^____-_~______________.___foo", id.GetSpectatordId()); } TEST(MeterIdTest, LookupTags) { - MeterId id1("foo", {{"a", "1"}, {"b", "2"}, {"c", "3"}}); - MeterId id2("foo", {{"c", "3"}, {"b", "2"}, {"a", "1"}}); + const MeterId id1("foo", {{"a", "1"}, {"b", "2"}, {"c", "3"}}); + const MeterId id2("foo", {{"c", "3"}, {"b", "2"}, {"a", "1"}}); std::unordered_map d; d[id1] = "test"; EXPECT_EQ("test", d[id2]); @@ -71,7 +71,7 @@ TEST(MeterIdTest, ToString) TEST(MeterIdTest, Tags) { MeterId id1("foo", {{"a", "1"}}); - std::unordered_map expected = {{"a", "1"}}; + const std::unordered_map expected = {{"a", "1"}}; EXPECT_EQ(expected, id1.GetTags()); } diff --git a/libs/meter/meter_types/test/test_age_gauge.cpp b/libs/meter/meter_types/test/test_age_gauge.cpp index 095bbf2..c6cefb7 100644 --- a/libs/meter/meter_types/test/test_age_gauge.cpp +++ b/libs/meter/meter_types/test/test_age_gauge.cpp @@ -3,7 +3,7 @@ #include -class AgeGaugeTest : public ::testing::Test +class AgeGaugeTest : public testing::Test { protected: MeterId tid = MeterId("age_gauge"); @@ -12,7 +12,7 @@ class AgeGaugeTest : public ::testing::Test TEST_F(AgeGaugeTest, Now) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); AgeGauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Now(); @@ -22,7 +22,7 @@ TEST_F(AgeGaugeTest, Now) TEST_F(AgeGaugeTest, Set) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); AgeGauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Set(10); diff --git a/libs/meter/meter_types/test/test_counter.cpp b/libs/meter/meter_types/test/test_counter.cpp index dbc4129..3a8e21e 100644 --- a/libs/meter/meter_types/test/test_counter.cpp +++ b/libs/meter/meter_types/test/test_counter.cpp @@ -3,7 +3,7 @@ #include -class CounterTest : public ::testing::Test +class CounterTest : public testing::Test { protected: MeterId tid = MeterId("counter"); @@ -12,7 +12,7 @@ class CounterTest : public ::testing::Test TEST_F(CounterTest, increment) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Counter c(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -25,7 +25,7 @@ TEST_F(CounterTest, increment) TEST_F(CounterTest, incrementNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Counter c(tid); c.Increment(-1); diff --git a/libs/meter/meter_types/test/test_dist_summary.cpp b/libs/meter/meter_types/test/test_dist_summary.cpp index 312b262..7695515 100644 --- a/libs/meter/meter_types/test/test_dist_summary.cpp +++ b/libs/meter/meter_types/test/test_dist_summary.cpp @@ -3,7 +3,7 @@ #include -class DistSummaryTest : public ::testing::Test +class DistSummaryTest : public testing::Test { protected: MeterId tid = MeterId("dist_summary"); @@ -12,7 +12,7 @@ class DistSummaryTest : public ::testing::Test TEST_F(DistSummaryTest, record) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); DistributionSummary ds(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -23,7 +23,7 @@ TEST_F(DistSummaryTest, record) TEST_F(DistSummaryTest, recordNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); DistributionSummary ds(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -34,7 +34,7 @@ TEST_F(DistSummaryTest, recordNegative) TEST_F(DistSummaryTest, recordZero) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); DistributionSummary ds(tid); EXPECT_TRUE(writer->IsEmpty()); diff --git a/libs/meter/meter_types/test/test_gauge.cpp b/libs/meter/meter_types/test/test_gauge.cpp index 466fe07..8de2060 100644 --- a/libs/meter/meter_types/test/test_gauge.cpp +++ b/libs/meter/meter_types/test/test_gauge.cpp @@ -3,7 +3,7 @@ #include -class GaugeTest : public ::testing::Test +class GaugeTest : public testing::Test { protected: MeterId tid = MeterId("gauge"); @@ -12,7 +12,7 @@ class GaugeTest : public ::testing::Test TEST_F(GaugeTest, Now) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Gauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Set(1); @@ -22,7 +22,7 @@ TEST_F(GaugeTest, Now) TEST_F(GaugeTest, TTL) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Gauge g(tid, 10); EXPECT_TRUE(writer->IsEmpty()); g.Set(42); diff --git a/libs/meter/meter_types/test/test_max_gauge.cpp b/libs/meter/meter_types/test/test_max_gauge.cpp index 573bcd6..b941bed 100644 --- a/libs/meter/meter_types/test/test_max_gauge.cpp +++ b/libs/meter/meter_types/test/test_max_gauge.cpp @@ -3,7 +3,7 @@ #include -class MaxGaugeTest : public ::testing::Test +class MaxGaugeTest : public testing::Test { protected: MeterId tid = MeterId("max_gauge"); @@ -12,7 +12,7 @@ class MaxGaugeTest : public ::testing::Test TEST_F(MaxGaugeTest, Set) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); MaxGauge g(tid); EXPECT_TRUE(writer->IsEmpty()); g.Set(0); diff --git a/libs/meter/meter_types/test/test_monotonic_counter.cpp b/libs/meter/meter_types/test/test_monotonic_counter.cpp index 7bed63a..dbef4af 100644 --- a/libs/meter/meter_types/test/test_monotonic_counter.cpp +++ b/libs/meter/meter_types/test/test_monotonic_counter.cpp @@ -3,7 +3,7 @@ #include -class MonotonicCounterTest : public ::testing::Test +class MonotonicCounterTest : public testing::Test { protected: MeterId tid = MeterId("monotonic_counter"); @@ -12,7 +12,7 @@ class MonotonicCounterTest : public ::testing::Test TEST_F(MonotonicCounterTest, SetValue) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); MonotonicCounter mc(tid); EXPECT_TRUE(writer->IsEmpty()); mc.Set(1); @@ -22,7 +22,7 @@ TEST_F(MonotonicCounterTest, SetValue) TEST_F(MonotonicCounterTest, SetNegativeValue) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); MonotonicCounter mc(tid); EXPECT_TRUE(writer->IsEmpty()); mc.Set(-1); diff --git a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp index 94aef7a..c921f83 100644 --- a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp +++ b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp @@ -3,7 +3,7 @@ #include -class MonoCounterTest : public ::testing::Test +class MonoCounterTest : public testing::Test { protected: MeterId tid = MeterId("monotonic_counter_uint"); @@ -12,7 +12,7 @@ class MonoCounterTest : public ::testing::Test TEST_F(MonoCounterTest, set) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); MonotonicCounterUint mc(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -23,7 +23,7 @@ TEST_F(MonoCounterTest, set) TEST_F(MonoCounterTest, setNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); MonotonicCounterUint mc(tid); EXPECT_TRUE(writer->IsEmpty()); diff --git a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp index e691a6f..907d456 100644 --- a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp +++ b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp @@ -3,7 +3,7 @@ #include -class PercentileDistSummaryTest : public ::testing::Test +class PercentileDistSummaryTest : public testing::Test { protected: MeterId tid = MeterId("percentile_dist_summary"); @@ -12,7 +12,7 @@ class PercentileDistSummaryTest : public ::testing::Test TEST_F(PercentileDistSummaryTest, record) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileDistributionSummary pds(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -23,7 +23,7 @@ TEST_F(PercentileDistSummaryTest, record) TEST_F(PercentileDistSummaryTest, recordNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileDistributionSummary pds(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -34,7 +34,7 @@ TEST_F(PercentileDistSummaryTest, recordNegative) TEST_F(PercentileDistSummaryTest, recordZero) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileDistributionSummary pds(tid); EXPECT_TRUE(writer->IsEmpty()); diff --git a/libs/meter/meter_types/test/test_percentile_timer.cpp b/libs/meter/meter_types/test/test_percentile_timer.cpp index 1d1f8ef..8f6731e 100644 --- a/libs/meter/meter_types/test/test_percentile_timer.cpp +++ b/libs/meter/meter_types/test/test_percentile_timer.cpp @@ -3,7 +3,7 @@ #include -class PercentileTimerTest : public ::testing::Test +class PercentileTimerTest : public testing::Test { protected: MeterId tid = MeterId("percentile_timer"); @@ -12,7 +12,7 @@ class PercentileTimerTest : public ::testing::Test TEST_F(PercentileTimerTest, record) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileTimer pt(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -23,7 +23,7 @@ TEST_F(PercentileTimerTest, record) TEST_F(PercentileTimerTest, recordNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileTimer pt(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -34,7 +34,7 @@ TEST_F(PercentileTimerTest, recordNegative) TEST_F(PercentileTimerTest, recordZero) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); PercentileTimer pt(tid); EXPECT_TRUE(writer->IsEmpty()); diff --git a/libs/meter/meter_types/test/test_timer.cpp b/libs/meter/meter_types/test/test_timer.cpp index 12aeced..3675c15 100644 --- a/libs/meter/meter_types/test/test_timer.cpp +++ b/libs/meter/meter_types/test/test_timer.cpp @@ -3,7 +3,7 @@ #include -class TimerTest : public ::testing::Test +class TimerTest : public testing::Test { protected: MeterId tid = MeterId("timer"); @@ -12,7 +12,7 @@ class TimerTest : public ::testing::Test TEST_F(TimerTest, record) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Timer t(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -23,7 +23,7 @@ TEST_F(TimerTest, record) TEST_F(TimerTest, recordNegative) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Timer t(tid); EXPECT_TRUE(writer->IsEmpty()); @@ -34,7 +34,7 @@ TEST_F(TimerTest, recordNegative) TEST_F(TimerTest, recordZero) { WriterTestHelper::InitializeWriter(WriterType::Memory); - auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); + const auto* writer = dynamic_cast(WriterTestHelper::GetImpl()); Timer t(tid); EXPECT_TRUE(writer->IsEmpty()); diff --git a/libs/utils/src/util.cpp b/libs/utils/src/util.cpp index 52aa9ca..e1e3a3e 100644 --- a/libs/utils/src/util.cpp +++ b/libs/utils/src/util.cpp @@ -23,7 +23,7 @@ std::optional ParseProtocolLine(const std::string& line) std::unordered_map tags{}; std::string value{}; - auto mainParts = split(line, ':'); + const auto mainParts = split(line, ':'); if (mainParts.size() < 3) { diff --git a/libs/writer/writer_config/test_writer_config.cpp b/libs/writer/writer_config/test_writer_config.cpp index 617a9cc..7b08fdd 100644 --- a/libs/writer/writer_config/test_writer_config.cpp +++ b/libs/writer/writer_config/test_writer_config.cpp @@ -39,7 +39,7 @@ class EnvironmentVariableGuard std::optional m_originalValue; }; -class WriterConfigTest : public ::testing::Test +class WriterConfigTest : public testing::Test { protected: EnvironmentVariableGuard envGuard{"SPECTATOR_OUTPUT_LOCATION"}; @@ -51,21 +51,21 @@ TEST_F(WriterConfigTest, BasicWriterTypes) { // Test "memory" type { - WriterConfig config(WriterTypes::Memory); + const WriterConfig config(WriterTypes::Memory); EXPECT_EQ(config.GetType(), WriterType::Memory); EXPECT_EQ(config.GetLocation(), DefaultLocations::NoLocation); } // Test "udp" type { - WriterConfig config(WriterTypes::UDP); + const WriterConfig config(WriterTypes::UDP); EXPECT_EQ(config.GetType(), WriterType::UDP); EXPECT_EQ(config.GetLocation(), DefaultLocations::UDP); } // Test "unix" type { - WriterConfig config(WriterTypes::Unix); + const WriterConfig config(WriterTypes::Unix); EXPECT_EQ(config.GetType(), WriterType::Unix); EXPECT_EQ(config.GetLocation(), DefaultLocations::UDS); } @@ -76,7 +76,7 @@ TEST_F(WriterConfigTest, URLBasedWriterTypes) // Test UDP URL { const std::string udpUrl = std::string(WriterTypes::UDPURL) + "192.168.1.100:8125"; - WriterConfig config(udpUrl); + const WriterConfig config(udpUrl); EXPECT_EQ(config.GetType(), WriterType::UDP); EXPECT_EQ(config.GetLocation(), udpUrl); } @@ -84,7 +84,7 @@ TEST_F(WriterConfigTest, URLBasedWriterTypes) // Test Unix domain socket URL { const std::string unixUrl = std::string(WriterTypes::UnixURL) + "/var/run/custom/socket.sock"; - WriterConfig config(unixUrl); + const WriterConfig config(unixUrl); EXPECT_EQ(config.GetType(), WriterType::Unix); EXPECT_EQ(config.GetLocation(), unixUrl); } @@ -93,7 +93,7 @@ TEST_F(WriterConfigTest, URLBasedWriterTypes) TEST_F(WriterConfigTest, BufferingConstructor) { - WriterConfig config(WriterTypes::UDP, 2048); + const WriterConfig config(WriterTypes::UDP, 2048); EXPECT_EQ(config.GetType(), WriterType::UDP); EXPECT_EQ(config.GetBufferSize(), 2048); EXPECT_TRUE(config.IsBufferingEnabled()); @@ -114,7 +114,7 @@ TEST_F(WriterConfigTest, EdgeCases) { // Test with just URL scheme but no path { - WriterConfig config("udp://"); + const WriterConfig config("udp://"); EXPECT_EQ(config.GetType(), WriterType::UDP); EXPECT_EQ(config.GetLocation(), "udp://"); } diff --git a/libs/writer/writer_config/writer_config.cpp b/libs/writer/writer_config/writer_config.cpp index 34906b3..41f86ec 100644 --- a/libs/writer/writer_config/writer_config.cpp +++ b/libs/writer/writer_config/writer_config.cpp @@ -35,7 +35,7 @@ WriterConfig::WriterConfig(const std::string& type) if (envLocation != nullptr) { Logger::debug("Using environment variable SPECTATOR_OUTPUT_LOCATION: {}", envLocation); - std::string envValue(envLocation); + const std::string envValue(envLocation); auto [writer_type, location] = GetWriterConfigFromString(envValue); m_type = writer_type; m_location = location; @@ -50,7 +50,7 @@ WriterConfig::WriterConfig(const std::string& type) Logger::debug("WriterConfig initialized with type: {}, location: {}", WriterTypeToString(m_type), m_location); } -WriterConfig::WriterConfig(const std::string& type, const unsigned int bufferSize) +WriterConfig::WriterConfig(const std::string& type, unsigned int bufferSize) : WriterConfig(type) // Constructor delegation { m_bufferSize = bufferSize; diff --git a/libs/writer/writer_config/writer_config.h b/libs/writer/writer_config/writer_config.h index 0640794..be564cf 100644 --- a/libs/writer/writer_config/writer_config.h +++ b/libs/writer/writer_config/writer_config.h @@ -9,11 +9,11 @@ class WriterConfig { public: WriterConfig(const std::string& type); - WriterConfig(const std::string& type, const unsigned int bufferSize); + WriterConfig(const std::string& type, unsigned int bufferSize); const WriterType& GetType() const noexcept { return m_type; } - const unsigned int GetBufferSize() const noexcept { return m_bufferSize; } - const bool IsBufferingEnabled() const noexcept { return m_isBufferingEnabled; } + unsigned int GetBufferSize() const noexcept { return m_bufferSize; } + bool IsBufferingEnabled() const noexcept { return m_isBufferingEnabled; } const std::string& GetLocation() const noexcept { return m_location; } private: diff --git a/libs/writer/writer_types/src/uds_writer.cpp b/libs/writer/writer_types/src/uds_writer.cpp index 4033605..78ab55b 100644 --- a/libs/writer/writer_types/src/uds_writer.cpp +++ b/libs/writer/writer_types/src/uds_writer.cpp @@ -35,7 +35,7 @@ bool UDSWriter::connect() } // Connect to the UDS server - local::stream_protocol::endpoint endpoint(m_socketPath); + const local::stream_protocol::endpoint endpoint(m_socketPath); boost::system::error_code ec; m_socket->connect(endpoint, ec); diff --git a/libs/writer/writer_types/test/test_memory_writer.cpp b/libs/writer/writer_types/test/test_memory_writer.cpp index 2aa46a2..d35b76b 100644 --- a/libs/writer/writer_types/test/test_memory_writer.cpp +++ b/libs/writer/writer_types/test/test_memory_writer.cpp @@ -3,7 +3,7 @@ TEST(MemoryWriterTest, IsEmpty) { - auto writer = MemoryWriter(); + const auto writer = MemoryWriter(); EXPECT_TRUE(writer.IsEmpty()); } diff --git a/libs/writer/writer_types/test/test_udp_writer.cpp b/libs/writer/writer_types/test/test_udp_writer.cpp index e79c682..11ddb4c 100644 --- a/libs/writer/writer_types/test/test_udp_writer.cpp +++ b/libs/writer/writer_types/test/test_udp_writer.cpp @@ -8,7 +8,7 @@ #include // For std::find // Test fixture for UDP Writer tests -class UDPWriterTest : public ::testing::Test +class UDPWriterTest : public testing::Test { protected: void SetUp() override @@ -52,7 +52,7 @@ TEST_F(UDPWriterTest, SendMessage) UDPWriter writer("127.0.0.1", 1234); // Define our test message - std::string test_message = "Hello from UDP Writer Test"; + const std::string test_message = "Hello from UDP Writer Test"; // Send a test message writer.Write(test_message); @@ -61,7 +61,7 @@ TEST_F(UDPWriterTest, SendMessage) std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Get current messages and verify the message was received - auto messages = get_messages(); + const auto messages = get_messages(); ASSERT_FALSE(messages.empty()); // Check that our message is in the vector @@ -74,6 +74,7 @@ TEST_F(UDPWriterTest, SendMessage) break; } } + ASSERT_TRUE(message_found); } TEST_F(UDPWriterTest, CloseAndReopen) @@ -112,7 +113,7 @@ TEST_F(UDPWriterTest, SendMultipleMessages) UDPWriter writer("127.0.0.1", 1234); // Define test messages - std::vector test_messages = {"Message 1", "Message 2", "Message 3"}; + const std::vector test_messages = {"Message 1", "Message 2", "Message 3"}; // Send several messages in succession for (const auto& msg : test_messages) @@ -124,7 +125,7 @@ TEST_F(UDPWriterTest, SendMultipleMessages) std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Get received messages and verify - auto received_messages = get_messages(); + const auto received_messages = get_messages(); // Verify we received at least the number of messages we sent ASSERT_EQ(received_messages.size(), test_messages.size()); diff --git a/libs/writer/writer_types/test/test_uds_writer.cpp b/libs/writer/writer_types/test/test_uds_writer.cpp index 9eb5318..f39ea14 100644 --- a/libs/writer/writer_types/test/test_uds_writer.cpp +++ b/libs/writer/writer_types/test/test_uds_writer.cpp @@ -8,7 +8,7 @@ #include // Test fixture for UDS Writer tests -class UDSWriterTest : public ::testing::Test +class UDSWriterTest : public testing::Test { protected: void SetUp() override @@ -52,7 +52,7 @@ TEST_F(UDSWriterTest, SendMessage) UDSWriter writer("/tmp/test_uds_socket"); // Define our test message - std::string test_message = "Hello from UDS Writer Test"; + const std::string test_message = "Hello from UDS Writer Test"; // Send a test message writer.Write(test_message); @@ -61,7 +61,7 @@ TEST_F(UDSWriterTest, SendMessage) std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Get current messages and verify the message was received - auto messages = get_uds_messages(); + const auto messages = get_uds_messages(); ASSERT_FALSE(messages.empty()); // Check that our message is in the vector @@ -81,7 +81,7 @@ TEST_F(UDSWriterTest, SendMessage) TEST_F(UDSWriterTest, CloseAndReopen) { UDSWriter writer("/tmp/test_uds_socket"); - std::string message1 = "Initial message"; + const std::string message1 = "Initial message"; writer.Write(message1); // Wait for message processing @@ -97,7 +97,7 @@ TEST_F(UDSWriterTest, CloseAndReopen) // Create a new writer UDSWriter writer2("/tmp/test_uds_socket"); - std::string message2 = "Message after reopening"; + const std::string message2 = "Message after reopening"; writer2.Write(message2); // Wait for message processing @@ -114,7 +114,7 @@ TEST_F(UDSWriterTest, SendMultipleMessages) UDSWriter writer("/tmp/test_uds_socket"); // Define test messages - std::vector test_messages = {"Message 1", "Message 2", "Message 3"}; + const std::vector test_messages = {"Message 1", "Message 2", "Message 3"}; // Send messages one by one, with a separate connection for each for (const auto& msg : test_messages) @@ -126,7 +126,7 @@ TEST_F(UDSWriterTest, SendMultipleMessages) std::this_thread::sleep_for(std::chrono::milliseconds(300)); // Get received messages and verify - auto received_messages = get_uds_messages(); + const auto received_messages = get_uds_messages(); // Verify we received the number of messages we sent ASSERT_EQ(received_messages.size(), test_messages.size()); diff --git a/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp b/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp index b7599d9..99b82d1 100644 --- a/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp +++ b/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp @@ -47,7 +47,7 @@ try boost::asio::io_context io_context; // Create an IPv4 socket bound to localhost (127.0.0.1) and port 1234 - boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string("127.0.0.1"), port); + const boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::address::from_string("127.0.0.1"), port); boost::asio::ip::udp::socket socket(io_context, boost::asio::ip::udp::v4()); try @@ -73,7 +73,7 @@ try { try { - std::size_t bytes_received = socket.receive_from(boost::asio::buffer(buffer), sender_endpoint); + const std::size_t bytes_received = socket.receive_from(boost::asio::buffer(buffer), sender_endpoint); if (bytes_received == buffer.size()) { diff --git a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp index 898459d..d6a63dd 100644 --- a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp +++ b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp @@ -55,7 +55,7 @@ try boost::asio::io_context io_context; // Create and open a Unix domain socket - boost::asio::local::stream_protocol::endpoint endpoint(socket_path); + const boost::asio::local::stream_protocol::endpoint endpoint(socket_path); boost::asio::local::stream_protocol::acceptor acceptor(io_context, endpoint); std::cout << "UDS server listening on " << socket_path << std::endl; @@ -81,11 +81,8 @@ try std::this_thread::sleep_for(std::chrono::milliseconds(50)); continue; } - else - { - std::cerr << "Error accepting connection: " << ec.message() << std::endl; - continue; - } + std::cerr << "Error accepting connection: " << ec.message() << std::endl; + continue; } // Connection accepted, set to non-blocking to avoid hanging @@ -115,7 +112,7 @@ try // Connection closed cleanly by peer break; } - else if (read_ec) + if (read_ec) { std::cerr << "Error reading from socket: " << read_ec.message() << std::endl; break; diff --git a/libs/writer/writer_wrapper/test_writer.cpp b/libs/writer/writer_wrapper/test_writer.cpp index f2f7794..58fd1ed 100644 --- a/libs/writer/writer_wrapper/test_writer.cpp +++ b/libs/writer/writer_wrapper/test_writer.cpp @@ -13,7 +13,7 @@ #include "../writer_types/test_utils/uds_server/uds_server.h" // Test fixture for UDS Writer tests -class WriterWrapperUDSWriterTest : public ::testing::Test +class WriterWrapperUDSWriterTest : public testing::Test { protected: void SetUp() override diff --git a/libs/writer/writer_wrapper/writer.cpp b/libs/writer/writer_wrapper/writer.cpp index c036869..ac2fbbe 100644 --- a/libs/writer/writer_wrapper/writer.cpp +++ b/libs/writer/writer_wrapper/writer.cpp @@ -94,7 +94,7 @@ void Writer::Reset() void Writer::TryToSend(const std::string& message) { - auto& instance = GetInstance(); + const auto& instance = GetInstance(); if (!instance.m_impl) { @@ -193,7 +193,7 @@ void Writer::Write(const std::string& message) void Writer::Close() { - auto& instance = GetInstance(); + const auto& instance = GetInstance(); if (!instance.m_impl) { From 985989d0a630e8a10c2104ca9dfe46bd98e0d536 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Wed, 18 Jun 2025 12:12:38 -0500 Subject: [PATCH 17/34] more clang tidy fixes --- libs/config/config.cpp | 6 +++--- libs/config/test_config.cpp | 6 +++--- libs/meter/meter_id/meter_id.cpp | 18 ++++++++--------- libs/meter/meter_id/test_meter_id.cpp | 4 ++-- libs/utils/include/util.h | 2 +- libs/utils/src/util.cpp | 2 +- .../writer_config/test_writer_config.cpp | 6 +++--- libs/writer/writer_config/writer_config.cpp | 8 +++----- libs/writer/writer_config/writer_config.h | 10 +++++----- libs/writer/writer_types/include/udp_writer.h | 1 - libs/writer/writer_types/src/udp_writer.cpp | 2 -- libs/writer/writer_types/src/uds_writer.cpp | 2 -- .../writer_types/test/test_udp_writer.cpp | 2 +- .../writer_types/test/test_uds_writer.cpp | 2 +- .../test_utils/udp_server/udp_server.cpp | 5 ++--- .../test_utils/uds_server/uds_server.cpp | 4 +--- libs/writer/writer_wrapper/test_writer.cpp | 8 ++++---- libs/writer/writer_wrapper/writer.cpp | 4 ++-- libs/writer/writer_wrapper/writer.h | 2 +- spectator/registry.h | 20 +++++++++---------- spectator/test_registry.cpp | 20 +++++++++---------- 21 files changed, 62 insertions(+), 72 deletions(-) diff --git a/libs/config/config.cpp b/libs/config/config.cpp index 14af771..ca780f6 100644 --- a/libs/config/config.cpp +++ b/libs/config/config.cpp @@ -25,11 +25,11 @@ std::unordered_map CalculateTags( valid_tags[ConfigConstants::process] = process_name; } - for (const auto& kv : tags) + for (const auto& [fst, snd] : tags) { - if (kv.first.empty() == false && kv.second.empty() == false) + if (fst.empty() == false && snd.empty() == false) { - valid_tags[kv.first] = kv.second; + valid_tags[fst] = snd; } } diff --git a/libs/config/test_config.cpp b/libs/config/test_config.cpp index a8f1c35..065c614 100644 --- a/libs/config/test_config.cpp +++ b/libs/config/test_config.cpp @@ -8,7 +8,7 @@ class EnvironmentVariableGuard { public: - EnvironmentVariableGuard(const std::string& name) : m_name(name) + explicit EnvironmentVariableGuard(const std::string& name) : m_name(name) { if (const char* value = std::getenv(name.c_str())) { @@ -16,9 +16,9 @@ class EnvironmentVariableGuard } } - void setValue(const std::string& value) { setenv(m_name.c_str(), value.c_str(), 1); } + void setValue(const std::string& value) const { setenv(m_name.c_str(), value.c_str(), 1); } - void unsetValue() { unsetenv(m_name.c_str()); } + void unsetValue() const { unsetenv(m_name.c_str()); } ~EnvironmentVariableGuard() { diff --git a/libs/meter/meter_id/meter_id.cpp b/libs/meter/meter_id/meter_id.cpp index 524021e..6de5f92 100644 --- a/libs/meter/meter_id/meter_id.cpp +++ b/libs/meter/meter_id/meter_id.cpp @@ -29,9 +29,9 @@ std::string ToSpectatorId(const std::string& name, const std::unordered_map::operator()(const MeterId& id) const { // Hash the name first - size_t name_hash = std::hash{}(id.GetName()); + const size_t name_hash = std::hash{}(id.GetName()); // Hash the tags size_t tags_hash = 0; - for (const auto& tag : id.GetTags()) + for (const auto& [fst, snd] : id.GetTags()) { // Combine key and value hashes - size_t pair_hash = std::hash{}(tag.first) ^ std::hash{}(tag.second) << 1; + const size_t pair_hash = std::hash{}(fst) ^ std::hash{}(snd) << 1; // Combine with the accumulated tags hash tags_hash ^= pair_hash + 0x9e3779b9 + (tags_hash << 6) + (tags_hash >> 2); } diff --git a/libs/meter/meter_id/test_meter_id.cpp b/libs/meter/meter_id/test_meter_id.cpp index b5dde3f..b024972 100644 --- a/libs/meter/meter_id/test_meter_id.cpp +++ b/libs/meter/meter_id/test_meter_id.cpp @@ -40,7 +40,7 @@ TEST(MeterIdTest, LookupTags) TEST(MeterIdTest, Name) { - MeterId id1("foo", {{"a", "1"}}); + const MeterId id1("foo", {{"a", "1"}}); EXPECT_EQ("foo", id1.GetName()); } @@ -70,7 +70,7 @@ TEST(MeterIdTest, ToString) TEST(MeterIdTest, Tags) { - MeterId id1("foo", {{"a", "1"}}); + const MeterId id1("foo", {{"a", "1"}}); const std::unordered_map expected = {{"a", "1"}}; EXPECT_EQ(expected, id1.GetTags()); } diff --git a/libs/utils/include/util.h b/libs/utils/include/util.h index 4a9139e..b778285 100644 --- a/libs/utils/include/util.h +++ b/libs/utils/include/util.h @@ -19,7 +19,7 @@ struct ProtocolLine return symbol == other.symbol && id == other.id && value == other.value; } - std::string to_string() const + [[nodiscard]] std::string to_string() const { std::stringstream ss; ss << symbol << ":" << id.GetName(); diff --git a/libs/utils/src/util.cpp b/libs/utils/src/util.cpp index e1e3a3e..e891e38 100644 --- a/libs/utils/src/util.cpp +++ b/libs/utils/src/util.cpp @@ -4,7 +4,7 @@ #include // Utility: split a string by a delimiter -std::vector split(const std::string& str, char delimiter) +std::vector split(const std::string& str, const char delimiter) { std::vector tokens; std::stringstream ss(str); diff --git a/libs/writer/writer_config/test_writer_config.cpp b/libs/writer/writer_config/test_writer_config.cpp index 7b08fdd..228fb75 100644 --- a/libs/writer/writer_config/test_writer_config.cpp +++ b/libs/writer/writer_config/test_writer_config.cpp @@ -10,7 +10,7 @@ class EnvironmentVariableGuard { public: - EnvironmentVariableGuard(const std::string& name) : m_name(name) + explicit EnvironmentVariableGuard(const std::string& name) : m_name(name) { if (const char* value = std::getenv(name.c_str())) { @@ -18,9 +18,9 @@ class EnvironmentVariableGuard } } - void setValue(const std::string& value) { setenv(m_name.c_str(), value.c_str(), 1); } + void setValue(const std::string& value) const { setenv(m_name.c_str(), value.c_str(), 1); } - void unsetValue() { unsetenv(m_name.c_str()); } + void unsetValue() const { unsetenv(m_name.c_str()); } ~EnvironmentVariableGuard() { diff --git a/libs/writer/writer_config/writer_config.cpp b/libs/writer/writer_config/writer_config.cpp index 41f86ec..1fd4ce0 100644 --- a/libs/writer/writer_config/writer_config.cpp +++ b/libs/writer/writer_config/writer_config.cpp @@ -10,8 +10,7 @@ struct WriterConfigConstants std::pair GetWriterConfigFromString(const std::string& type) { // Check exact matches first - auto it = TypeToLocationMap.find(type); - if (it != TypeToLocationMap.end()) + if (const auto it = TypeToLocationMap.find(type); it != TypeToLocationMap.end()) { return {it->second.first, std::string(it->second.second)}; } @@ -31,8 +30,7 @@ std::pair GetWriterConfigFromString(const std::string& WriterConfig::WriterConfig(const std::string& type) { - const char* envLocation = std::getenv("SPECTATOR_OUTPUT_LOCATION"); - if (envLocation != nullptr) + if (const char* envLocation = std::getenv("SPECTATOR_OUTPUT_LOCATION"); envLocation != nullptr) { Logger::debug("Using environment variable SPECTATOR_OUTPUT_LOCATION: {}", envLocation); const std::string envValue(envLocation); @@ -50,7 +48,7 @@ WriterConfig::WriterConfig(const std::string& type) Logger::debug("WriterConfig initialized with type: {}, location: {}", WriterTypeToString(m_type), m_location); } -WriterConfig::WriterConfig(const std::string& type, unsigned int bufferSize) +WriterConfig::WriterConfig(const std::string& type, const unsigned int bufferSize) : WriterConfig(type) // Constructor delegation { m_bufferSize = bufferSize; diff --git a/libs/writer/writer_config/writer_config.h b/libs/writer/writer_config/writer_config.h index be564cf..12d5074 100644 --- a/libs/writer/writer_config/writer_config.h +++ b/libs/writer/writer_config/writer_config.h @@ -8,13 +8,13 @@ class WriterConfig { public: - WriterConfig(const std::string& type); + explicit WriterConfig(const std::string& type); WriterConfig(const std::string& type, unsigned int bufferSize); - const WriterType& GetType() const noexcept { return m_type; } - unsigned int GetBufferSize() const noexcept { return m_bufferSize; } - bool IsBufferingEnabled() const noexcept { return m_isBufferingEnabled; } - const std::string& GetLocation() const noexcept { return m_location; } + [[nodiscard]] const WriterType& GetType() const noexcept { return m_type; } + [[nodiscard]] unsigned int GetBufferSize() const noexcept { return m_bufferSize; } + [[nodiscard]] bool IsBufferingEnabled() const noexcept { return m_isBufferingEnabled; } + [[nodiscard]] const std::string& GetLocation() const noexcept { return m_location; } private: WriterType m_type; diff --git a/libs/writer/writer_types/include/udp_writer.h b/libs/writer/writer_types/include/udp_writer.h index 0615f34..72d9119 100644 --- a/libs/writer/writer_types/include/udp_writer.h +++ b/libs/writer/writer_types/include/udp_writer.h @@ -2,7 +2,6 @@ #include #include -#include #include class UDPWriter final : public BaseWriter diff --git a/libs/writer/writer_types/src/udp_writer.cpp b/libs/writer/writer_types/src/udp_writer.cpp index 9aca429..2087f67 100644 --- a/libs/writer/writer_types/src/udp_writer.cpp +++ b/libs/writer/writer_types/src/udp_writer.cpp @@ -2,8 +2,6 @@ #include -#include - UDPWriter::UDPWriter(const std::string& host, int port) : m_host(host), m_port(port) { try diff --git a/libs/writer/writer_types/src/uds_writer.cpp b/libs/writer/writer_types/src/uds_writer.cpp index 78ab55b..07fbfa9 100644 --- a/libs/writer/writer_types/src/uds_writer.cpp +++ b/libs/writer/writer_types/src/uds_writer.cpp @@ -3,8 +3,6 @@ #include #include -#include -#include namespace local = boost::asio::local; diff --git a/libs/writer/writer_types/test/test_udp_writer.cpp b/libs/writer/writer_types/test/test_udp_writer.cpp index 11ddb4c..0fa09e8 100644 --- a/libs/writer/writer_types/test/test_udp_writer.cpp +++ b/libs/writer/writer_types/test/test_udp_writer.cpp @@ -21,7 +21,7 @@ class UDPWriterTest : public testing::Test // Start the UDP server in a separate thread server_thread = std::thread( - []() + [] { // This calls our server function directly listen_for_udp_messages(); diff --git a/libs/writer/writer_types/test/test_uds_writer.cpp b/libs/writer/writer_types/test/test_uds_writer.cpp index f39ea14..0274edf 100644 --- a/libs/writer/writer_types/test/test_uds_writer.cpp +++ b/libs/writer/writer_types/test/test_uds_writer.cpp @@ -21,7 +21,7 @@ class UDSWriterTest : public testing::Test // Start the UDS server in a separate thread server_thread = std::thread( - []() + [] { // This calls our server function directly listen_for_uds_messages(); diff --git a/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp b/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp index 99b82d1..46f0964 100644 --- a/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp +++ b/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -42,7 +41,7 @@ void add_message(const std::string& message) void listen_for_udp_messages() try { - const unsigned short port = 1234; + constexpr auto port = 1234; boost::asio::io_context io_context; @@ -61,7 +60,7 @@ try throw; } - std::array buffer; + std::array buffer{}; boost::asio::ip::udp::endpoint sender_endpoint; std::cout << "UDP server listening on 127.0.0.1:" << port << " (IPv4 localhost)\n"; diff --git a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp index d6a63dd..b6e4342 100644 --- a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp +++ b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp @@ -1,6 +1,5 @@ #include "uds_server.h" #include -#include #include #include #include @@ -8,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -89,7 +87,7 @@ try socket.non_blocking(true); // Buffer for reading data - std::array buffer; + std::array buffer{}; while (uds_server_running) { // We need to handle both data availability and potential errors diff --git a/libs/writer/writer_wrapper/test_writer.cpp b/libs/writer/writer_wrapper/test_writer.cpp index 58fd1ed..c98a418 100644 --- a/libs/writer/writer_wrapper/test_writer.cpp +++ b/libs/writer/writer_wrapper/test_writer.cpp @@ -26,7 +26,7 @@ class WriterWrapperUDSWriterTest : public testing::Test // Start the UDS server in a separate thread server_thread = std::thread( - []() + [] { // This calls our server function directly listen_for_uds_messages(); @@ -60,9 +60,9 @@ TEST_F(WriterWrapperUDSWriterTest, MultithreadedWrite) WriterTestHelper::InitializeWriter(WriterType::Unix, unixUrl, 0, 30); // Number of threads and counters to create - const int numThreads = 4; - const int countersPerThread = 3; - const int incrementsPerCounter = 5; + constexpr auto numThreads = 4; + constexpr auto countersPerThread = 3; + constexpr auto incrementsPerCounter = 5; // Function for worker threads auto worker = [&](int threadId) diff --git a/libs/writer/writer_wrapper/writer.cpp b/libs/writer/writer_wrapper/writer.cpp index ac2fbbe..020b38c 100644 --- a/libs/writer/writer_wrapper/writer.cpp +++ b/libs/writer/writer_wrapper/writer.cpp @@ -4,7 +4,7 @@ #include #include -static const char NEW_LINE = '\n'; +static constexpr auto NEW_LINE = '\n'; Writer::~Writer() { @@ -182,7 +182,7 @@ void Writer::Write(const std::string& message) try { // Call the member function using the pointer-to-member syntax - (instance.*(instance.writeImpl))(message); + (instance.*instance.writeImpl)(message); Logger::debug("Message written successfully: {}", message); } catch (const std::exception& e) diff --git a/libs/writer/writer_wrapper/writer.h b/libs/writer/writer_wrapper/writer.h index d849968..b6b9eec 100644 --- a/libs/writer/writer_wrapper/writer.h +++ b/libs/writer/writer_wrapper/writer.h @@ -9,7 +9,7 @@ class Writer final : public Singleton { public: - virtual ~Writer(); + ~Writer() override; private: friend class Singleton; diff --git a/spectator/registry.h b/spectator/registry.h index 874786f..4d20eea 100644 --- a/spectator/registry.h +++ b/spectator/registry.h @@ -23,58 +23,58 @@ class Registry AgeGauge age_gauge(const std::string& name, const std::unordered_map& tags = std::unordered_map()) const; - AgeGauge age_gauge_with_id(const MeterId& meter_id); + static AgeGauge age_gauge_with_id(const MeterId& meter_id); Counter counter(const std::string& name, const std::unordered_map& tags = std::unordered_map()) const; - Counter counter_with_id(const MeterId& meter_id); + static Counter counter_with_id(const MeterId& meter_id); DistributionSummary distribution_summary( const std::string& name, const std::unordered_map& tags = std::unordered_map()) const; - DistributionSummary distribution_summary_with_id(const MeterId& meter_id); + static DistributionSummary distribution_summary_with_id(const MeterId& meter_id); Gauge gauge( const std::string& name, const std::unordered_map& tags = std::unordered_map(), const std::optional& ttl_seconds = std::nullopt) const; - Gauge gauge_with_id(const MeterId& meter_id, const std::optional& ttl_seconds = std::nullopt); + static Gauge gauge_with_id(const MeterId& meter_id, const std::optional& ttl_seconds = std::nullopt); MaxGauge max_gauge(const std::string& name, const std::unordered_map& tags = std::unordered_map()) const; - MaxGauge max_gauge_with_id(const MeterId& meter_id); + static MaxGauge max_gauge_with_id(const MeterId& meter_id); MonotonicCounter monotonic_counter( const std::string& name, const std::unordered_map& tags = std::unordered_map()) const; - MonotonicCounter monotonic_counter_with_id(const MeterId& meter_id); + static MonotonicCounter monotonic_counter_with_id(const MeterId& meter_id); MonotonicCounterUint monotonic_counter_uint( const std::string& name, const std::unordered_map& tags = std::unordered_map()) const; - MonotonicCounterUint monotonic_counter_uint_with_id(const MeterId& meter_id); + static MonotonicCounterUint monotonic_counter_uint_with_id(const MeterId& meter_id); PercentileDistributionSummary pct_distribution_summary( const std::string& name, const std::unordered_map& tags = std::unordered_map()) const; - PercentileDistributionSummary pct_distribution_summary_with_id(const MeterId& meter_id); + static PercentileDistributionSummary pct_distribution_summary_with_id(const MeterId& meter_id); PercentileTimer pct_timer(const std::string& name, const std::unordered_map& tags = std::unordered_map()) const; - PercentileTimer pct_timer_with_id(const MeterId& meter_id); + static PercentileTimer pct_timer_with_id(const MeterId& meter_id); Timer timer(const std::string& name, const std::unordered_map& tags = std::unordered_map()) const; - Timer timer_with_id(const MeterId& meter_id); + static Timer timer_with_id(const MeterId& meter_id); private: Config m_config; diff --git a/spectator/test_registry.cpp b/spectator/test_registry.cpp index 315ddc5..7011184 100644 --- a/spectator/test_registry.cpp +++ b/spectator/test_registry.cpp @@ -43,7 +43,7 @@ TEST(RegistryTest, AgeGaugeWithId) auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - auto g = r.age_gauge_with_id(r.new_id("age_gauge", {{"my-tags", "bar"}})); + auto g = Registry::age_gauge_with_id(r.new_id("age_gauge", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(0); @@ -83,7 +83,7 @@ TEST(RegistryTest, CounterWithId) auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - auto c = r.counter_with_id(r.new_id("counter", {{"my-tags", "bar"}})); + auto c = Registry::counter_with_id(r.new_id("counter", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); c.Increment(); @@ -118,7 +118,7 @@ TEST(RegistryTest, DistributionSummaryWithId) auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - auto d = r.distribution_summary_with_id(r.new_id("distribution_summary", {{"my-tags", "bar"}})); + auto d = Registry::distribution_summary_with_id(r.new_id("distribution_summary", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); d.Record(42); @@ -145,7 +145,7 @@ TEST(RegistryTest, GaugeWithId) auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - auto g = r.gauge_with_id(r.new_id("gauge", {{"my-tags", "bar"}})); + auto g = Registry::gauge_with_id(r.new_id("gauge", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(42); @@ -197,7 +197,7 @@ TEST(RegistryTest, MaxGaugeWithId) auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - auto g = r.max_gauge_with_id(r.new_id("max_gauge", {{"my-tags", "bar"}})); + auto g = Registry::max_gauge_with_id(r.new_id("max_gauge", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); g.Set(42); @@ -224,7 +224,7 @@ TEST(RegistryTest, MonotonicCounterWithId) auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - auto c = r.monotonic_counter_with_id(r.new_id("monotonic_counter", {{"my-tags", "bar"}})); + auto c = Registry::monotonic_counter_with_id(r.new_id("monotonic_counter", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); c.Set(42); @@ -251,7 +251,7 @@ TEST(RegistryTest, MonotonicCounterUintWithId) auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - auto c = r.monotonic_counter_uint_with_id(r.new_id("monotonic_counter_uint", {{"my-tags", "bar"}})); + auto c = Registry::monotonic_counter_uint_with_id(r.new_id("monotonic_counter_uint", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); c.Set(42); @@ -291,7 +291,7 @@ TEST(RegistryTest, PctDistributionSummaryWithId) auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - auto d = r.pct_distribution_summary_with_id(r.new_id("pct_distribution_summary", {{"my-tags", "bar"}})); + auto d = Registry::pct_distribution_summary_with_id(r.new_id("pct_distribution_summary", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); d.Record(42); @@ -318,7 +318,7 @@ TEST(RegistryTest, PctTimerWithId) auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - auto t = r.pct_timer_with_id(r.new_id("pct_timer", {{"my-tags", "bar"}})); + auto t = Registry::pct_timer_with_id(r.new_id("pct_timer", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); t.Record(42); @@ -345,7 +345,7 @@ TEST(RegistryTest, TimerWithId) auto r = Registry(config); auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); - auto t = r.timer_with_id(r.new_id("timer", {{"my-tags", "bar"}})); + auto t = Registry::timer_with_id(r.new_id("timer", {{"my-tags", "bar"}})); EXPECT_TRUE(memoryWriter->IsEmpty()); t.Record(42); From 71c82057f0fd3fdfc46830340ecf9865e434e8da Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Wed, 18 Jun 2025 12:45:10 -0500 Subject: [PATCH 18/34] add performance test --- CMakeLists.txt | 2 +- performance_tests/CMakeLists.txt | 3 ++ performance_tests/udp_test.cpp | 50 ++++++++++++++++++++++++++++++++ spectator/registry.h | 1 + 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 performance_tests/CMakeLists.txt create mode 100644 performance_tests/udp_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a82ce1c..902405d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,4 +22,4 @@ endif() # Add subdirectories add_subdirectory(libs) add_subdirectory(spectator) - +add_subdirectory(performance_tests) diff --git a/performance_tests/CMakeLists.txt b/performance_tests/CMakeLists.txt new file mode 100644 index 0000000..bca70c7 --- /dev/null +++ b/performance_tests/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(udp_performance_test udp_test.cpp) +target_link_libraries(udp_performance_test PRIVATE registry) +add_test(NAME udp_performance_test COMMAND udp_performance_test) \ No newline at end of file diff --git a/performance_tests/udp_test.cpp b/performance_tests/udp_test.cpp new file mode 100644 index 0000000..c4a492f --- /dev/null +++ b/performance_tests/udp_test.cpp @@ -0,0 +1,50 @@ +#include +#include +#include +#include +#include +#include + + +int main() +{ + Logger::info("Starting UDP performance test..."); + + auto r = Registry(Config(WriterConfig(WriterTypes::UDP))); + std::unordered_map tags = { {"location", "udp"}, {"version", "correct-horse-battery-staple"}}; + + // Set maximum duration to 2 minutes + constexpr int max_duration_seconds = 2 * 60; + + // Track iterations and timing + unsigned long long iterations = 0; + auto start_time = std::chrono::steady_clock::now(); + + // Helper function to get elapsed time in seconds + auto elapsed = [&start_time]() -> double { + auto now = std::chrono::steady_clock::now(); + return std::chrono::duration(now - start_time).count(); + }; + + while (true) + { + r.counter("udp_test_counter", tags).Increment(); + iterations++; + + if (iterations % 500000 == 0) + { + if (elapsed() > max_duration_seconds) + { + break; + } + } + } + + double total_elapsed = elapsed(); + double rate_per_second = iterations / total_elapsed; + + Logger::info("Iterations completed: {}", iterations); + Logger::info("Total elapsed time: {:.2f} seconds", total_elapsed); + Logger::info("Rate: {:.2f} iterations/second", rate_per_second); + return 0; +} \ No newline at end of file diff --git a/spectator/registry.h b/spectator/registry.h index 4d20eea..148a52f 100644 --- a/spectator/registry.h +++ b/spectator/registry.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include From 465523660a5048a53c778708c03ea61ad617819a Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Wed, 18 Jun 2025 12:56:50 -0500 Subject: [PATCH 19/34] update tests --- libs/writer/writer_types/test/test_udp_writer.cpp | 8 ++++---- .../writer_types/test_utils/udp_server/udp_server.cpp | 2 +- performance_tests/CMakeLists.txt | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/libs/writer/writer_types/test/test_udp_writer.cpp b/libs/writer/writer_types/test/test_udp_writer.cpp index 0fa09e8..5261dd6 100644 --- a/libs/writer/writer_types/test/test_udp_writer.cpp +++ b/libs/writer/writer_types/test/test_udp_writer.cpp @@ -49,7 +49,7 @@ class UDPWriterTest : public testing::Test TEST_F(UDPWriterTest, SendMessage) { // Create a UDP writer that will connect to localhost:1234 - UDPWriter writer("127.0.0.1", 1234); + UDPWriter writer("127.0.0.1", 12345); // Define our test message const std::string test_message = "Hello from UDP Writer Test"; @@ -79,7 +79,7 @@ TEST_F(UDPWriterTest, SendMessage) TEST_F(UDPWriterTest, CloseAndReopen) { - UDPWriter writer("127.0.0.1", 1234); + UDPWriter writer("127.0.0.1", 12345); std::string message1 = "Initial message"; writer.Write(message1); @@ -95,7 +95,7 @@ TEST_F(UDPWriterTest, CloseAndReopen) writer.Close(); // Create a new writer - UDPWriter writer2("127.0.0.1", 1234); + UDPWriter writer2("127.0.0.1", 12345); std::string message2 = "Message after reopening"; writer2.Write(message2); @@ -110,7 +110,7 @@ TEST_F(UDPWriterTest, CloseAndReopen) TEST_F(UDPWriterTest, SendMultipleMessages) { - UDPWriter writer("127.0.0.1", 1234); + UDPWriter writer("127.0.0.1", 12345); // Define test messages const std::vector test_messages = {"Message 1", "Message 2", "Message 3"}; diff --git a/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp b/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp index 46f0964..549bf80 100644 --- a/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp +++ b/libs/writer/writer_types/test_utils/udp_server/udp_server.cpp @@ -41,7 +41,7 @@ void add_message(const std::string& message) void listen_for_udp_messages() try { - constexpr auto port = 1234; + constexpr auto port = 12345; boost::asio::io_context io_context; diff --git a/performance_tests/CMakeLists.txt b/performance_tests/CMakeLists.txt index bca70c7..964bf8d 100644 --- a/performance_tests/CMakeLists.txt +++ b/performance_tests/CMakeLists.txt @@ -1,3 +1,2 @@ add_executable(udp_performance_test udp_test.cpp) -target_link_libraries(udp_performance_test PRIVATE registry) -add_test(NAME udp_performance_test COMMAND udp_performance_test) \ No newline at end of file +target_link_libraries(udp_performance_test PRIVATE registry) \ No newline at end of file From 06ab80ec35615e69dadc981ebaeed9ae79af7caf Mon Sep 17 00:00:00 2001 From: Netflix Privileged User Date: Wed, 18 Jun 2025 19:15:18 +0000 Subject: [PATCH 20/34] get udp perf test working --- libs/logger/logger.h | 29 ++++++++++---- libs/writer/writer_config/writer_config.h | 2 +- libs/writer/writer_types/src/udp_writer.cpp | 6 +-- performance_tests/udp_test.cpp | 9 +++-- spectator/registry.cpp | 43 ++++++++++++++++++++- 5 files changed, 72 insertions(+), 17 deletions(-) diff --git a/libs/logger/logger.h b/libs/logger/logger.h index 1449ebe..f68e8c5 100644 --- a/libs/logger/logger.h +++ b/libs/logger/logger.h @@ -17,6 +17,7 @@ class Logger final : public Singleton { private: spdlog::logger* m_logger; // Use raw pointer, not unique_ptr + inline static bool s_loggingEnabled = false; // Static flag to control logging (C++17 inline initialization) friend class Singleton; @@ -48,35 +49,47 @@ class Logger final : public Singleton public: static spdlog::logger* GetLogger() { return GetInstance().m_logger; } - static void debug(const std::string& msg) { GetLogger()->debug(msg); } + static void debug(const std::string& msg) + { + if (s_loggingEnabled) GetLogger()->debug(msg); + } - static void info(const std::string& msg) { GetLogger()->info(msg); } + static void info(const std::string& msg) + { + if (s_loggingEnabled) GetLogger()->info(msg); + } - static void warn(const std::string& msg) { GetLogger()->warn(msg); } + static void warn(const std::string& msg) + { + if (s_loggingEnabled) GetLogger()->warn(msg); + } - static void error(const std::string& msg) { GetLogger()->error(msg); } + static void error(const std::string& msg) + { + if (s_loggingEnabled) GetLogger()->error(msg); + } template static void debug(fmt::format_string fmt, Args&&... args) { - GetLogger()->debug(fmt, std::forward(args)...); + if (s_loggingEnabled) GetLogger()->debug(fmt, std::forward(args)...); } template static void info(fmt::format_string fmt, Args&&... args) { - GetLogger()->info(fmt, std::forward(args)...); + if (s_loggingEnabled) GetLogger()->info(fmt, std::forward(args)...); } template static void warn(fmt::format_string fmt, Args&&... args) { - GetLogger()->warn(fmt, std::forward(args)...); + if (s_loggingEnabled) GetLogger()->warn(fmt, std::forward(args)...); } template static void error(fmt::format_string fmt, Args&&... args) { - GetLogger()->error(fmt, std::forward(args)...); + if (s_loggingEnabled) GetLogger()->error(fmt, std::forward(args)...); } }; \ No newline at end of file diff --git a/libs/writer/writer_config/writer_config.h b/libs/writer/writer_config/writer_config.h index 12d5074..0da7610 100644 --- a/libs/writer/writer_config/writer_config.h +++ b/libs/writer/writer_config/writer_config.h @@ -19,6 +19,6 @@ class WriterConfig private: WriterType m_type; std::string m_location; - unsigned int m_bufferSize; + unsigned int m_bufferSize = 0; bool m_isBufferingEnabled = false; }; \ No newline at end of file diff --git a/libs/writer/writer_types/src/udp_writer.cpp b/libs/writer/writer_types/src/udp_writer.cpp index 2087f67..5d1cdf0 100644 --- a/libs/writer/writer_types/src/udp_writer.cpp +++ b/libs/writer/writer_types/src/udp_writer.cpp @@ -26,8 +26,7 @@ UDPWriter::UDPWriter(const std::string& host, int port) : m_host(host), m_port(p UDPWriter::~UDPWriter() { Close(); } -void UDPWriter::Write(const std::string& message) -try +void UDPWriter::Write(const std::string& message) try { if (m_socket == nullptr || m_socket->is_open() == false) { @@ -52,8 +51,7 @@ catch (const std::exception& e) Logger::error("UDPWriter: Exception during write: {}", e.what()); } -void UDPWriter::Close() -try +void UDPWriter::Close() try { if (m_socket && m_socket->is_open()) { diff --git a/performance_tests/udp_test.cpp b/performance_tests/udp_test.cpp index c4a492f..6d6656a 100644 --- a/performance_tests/udp_test.cpp +++ b/performance_tests/udp_test.cpp @@ -43,8 +43,11 @@ int main() double total_elapsed = elapsed(); double rate_per_second = iterations / total_elapsed; - Logger::info("Iterations completed: {}", iterations); - Logger::info("Total elapsed time: {:.2f} seconds", total_elapsed); - Logger::info("Rate: {:.2f} iterations/second", rate_per_second); + //Logger::info("Iterations completed: {}", iterations); + //Logger::info("Total elapsed time: {:.2f} seconds", total_elapsed); + //Logger::info("Rate: {:.2f} iterations/second", rate_per_second); + std::cout << "Iterations completed: " << iterations << std::endl; + std::cout << "Total elapsed time: " << std::fixed << std::setprecision(2) << total_elapsed << " seconds" << std::endl; + std::cout << "Rate: " << std::fixed << std::setprecision(2) << rate_per_second << " iterations/second" << std::endl; return 0; } \ No newline at end of file diff --git a/spectator/registry.cpp b/spectator/registry.cpp index 5db9100..1b3c700 100644 --- a/spectator/registry.cpp +++ b/spectator/registry.cpp @@ -1,6 +1,47 @@ #include -Registry::Registry(const Config& config) : m_config(config) { Writer::Initialize(config.GetWriterType()); } + +std::pair ParseUdpAddress(const std::string& address) +{ + + std::regex pattern("udp://([0-9.]+):(\\d+)"); + std::smatch matches; + + if (!std::regex_match(address, matches, pattern) || matches.size() != 3) + { + throw std::runtime_error("Invalid UDP address format"); + } + + std::string ip = matches[1].str(); + int port = std::stoi(matches[2]); + + // Optional: Validate port range + if (port < 0 || port > 65535) + throw std::runtime_error("Port number out of valid range (0-65535)"); + + return {ip, port}; +} + +Registry::Registry(const Config& config) : m_config(config) +{ + if (config.GetWriterType() == WriterType::Memory) + { + Logger::info("Registry initializing Memory Writer"); + Writer::Initialize(config.GetWriterType()); + } + else if (config.GetWriterType() == WriterType::UDP) + { + auto [ip, port] = ParseUdpAddress(this->m_config.GetWriterLocation()); + Logger::info("Registry initializing UDP Writer at {}:{}", ip, port); + Writer::Initialize(config.GetWriterType(), ip, port); + + } + else if (config.GetWriterType() == WriterType::Unix) + { + Logger::info("Registry initializing UDS Writer at {null}:{null}"); + //Writer::Initialize(config.GetWriterType()); + } +} Registry::~Registry() { From 3c0051c9f85f7e3388cb074c2a40608b7fa80e76 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Thu, 19 Jun 2025 11:57:07 -0500 Subject: [PATCH 21/34] add uds test and buffering tests --- libs/config/config.h | 2 + performance_tests/CMakeLists.txt | 5 ++- performance_tests/udp_test.cpp | 40 +++++++++++++---- performance_tests/uds_test.cpp | 77 ++++++++++++++++++++++++++++++++ spectator/registry.cpp | 20 +++++++-- 5 files changed, 131 insertions(+), 13 deletions(-) create mode 100644 performance_tests/uds_test.cpp diff --git a/libs/config/config.h b/libs/config/config.h index 5be25a5..0ecd7dd 100644 --- a/libs/config/config.h +++ b/libs/config/config.h @@ -20,6 +20,8 @@ class Config const std::string& GetWriterLocation() const noexcept { return m_writerConfig.GetLocation(); } const WriterType& GetWriterType() const noexcept { return m_writerConfig.GetType(); } + const unsigned int GetWriterBufferSize() const noexcept { return m_writerConfig.GetBufferSize(); } + private: std::unordered_map m_extraTags; diff --git a/performance_tests/CMakeLists.txt b/performance_tests/CMakeLists.txt index 964bf8d..95fabe8 100644 --- a/performance_tests/CMakeLists.txt +++ b/performance_tests/CMakeLists.txt @@ -1,2 +1,5 @@ add_executable(udp_performance_test udp_test.cpp) -target_link_libraries(udp_performance_test PRIVATE registry) \ No newline at end of file +target_link_libraries(udp_performance_test PRIVATE registry) + +add_executable(uds_performance_test uds_test.cpp) +target_link_libraries(uds_performance_test PRIVATE registry) \ No newline at end of file diff --git a/performance_tests/udp_test.cpp b/performance_tests/udp_test.cpp index 6d6656a..6193284 100644 --- a/performance_tests/udp_test.cpp +++ b/performance_tests/udp_test.cpp @@ -4,14 +4,40 @@ #include #include #include +#include - -int main() +int main(int argc, char* argv[]) { - Logger::info("Starting UDP performance test..."); + if (argc > 2) + { + std::cerr << "Too many arguments provided." << std::endl; + return 1; + } + + bool bufferingEnabled = false; - auto r = Registry(Config(WriterConfig(WriterTypes::UDP))); - std::unordered_map tags = { {"location", "udp"}, {"version", "correct-horse-battery-staple"}}; + // If argument is provided and equals 1, enable buffering + if (argc == 2) { + if (std::string(argv[1]) == "1") { + bufferingEnabled = true; + } else { + std::cerr << "Usage: " << argv[0] << " [1]" << std::endl; + std::cerr << " No argument: Run without buffering" << std::endl; + std::cerr << " 1: Run with buffering enabled" << std::endl; + return 1; + } + } + // No arguments means bufferingEnabled remains false + Logger::info("Starting UDP performance test with buffering {}", bufferingEnabled ? "enabled" : "disabled"); + + // Configure the registry with or without buffering based on the command line argument + auto writerConfig = WriterConfig(WriterTypes::UDP); + if (bufferingEnabled) + { + writerConfig = WriterConfig(WriterTypes::UDP, 4096); + } + auto r = Registry(Config(writerConfig)); + std::unordered_map tags = { {"location", "udp"}, {"version", "correct-horse-battery-staple"}}; // Set maximum duration to 2 minutes constexpr int max_duration_seconds = 2 * 60; @@ -43,9 +69,7 @@ int main() double total_elapsed = elapsed(); double rate_per_second = iterations / total_elapsed; - //Logger::info("Iterations completed: {}", iterations); - //Logger::info("Total elapsed time: {:.2f} seconds", total_elapsed); - //Logger::info("Rate: {:.2f} iterations/second", rate_per_second); + std::cout << "Buffering enabled: " << (bufferingEnabled ? "Yes" : "No") << std::endl; std::cout << "Iterations completed: " << iterations << std::endl; std::cout << "Total elapsed time: " << std::fixed << std::setprecision(2) << total_elapsed << " seconds" << std::endl; std::cout << "Rate: " << std::fixed << std::setprecision(2) << rate_per_second << " iterations/second" << std::endl; diff --git a/performance_tests/uds_test.cpp b/performance_tests/uds_test.cpp new file mode 100644 index 0000000..a9f7a36 --- /dev/null +++ b/performance_tests/uds_test.cpp @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + if (argc > 2) + { + std::cerr << "Too many arguments provided." << std::endl; + return 1; + } + + bool bufferingEnabled = false; + + // If argument is provided and equals 1, enable buffering + if (argc == 2) { + if (std::string(argv[1]) == "1") { + bufferingEnabled = true; + } else { + std::cerr << "Usage: " << argv[0] << " [1]" << std::endl; + std::cerr << " No argument: Run without buffering" << std::endl; + std::cerr << " 1: Run with buffering enabled" << std::endl; + return 1; + } + } + // No arguments means bufferingEnabled remains false + Logger::info("Starting UDP performance test with buffering {}", bufferingEnabled ? "enabled" : "disabled"); + + // Configure the registry with or without buffering based on the command line argument + auto writerConfig = WriterConfig(WriterTypes::Unix); + if (bufferingEnabled) + { + writerConfig = WriterConfig(WriterTypes::Unix, 4096); + } + auto r = Registry(Config(writerConfig)); + std::unordered_map tags = { {"location", "unix"}, {"version", "correct-horse-battery-staple"}}; + + // Set maximum duration to 2 minutes + constexpr int max_duration_seconds = 2 * 60; + + // Track iterations and timing + unsigned long long iterations = 0; + auto start_time = std::chrono::steady_clock::now(); + + // Helper function to get elapsed time in seconds + auto elapsed = [&start_time]() -> double { + auto now = std::chrono::steady_clock::now(); + return std::chrono::duration(now - start_time).count(); + }; + + while (true) + { + r.counter("unix_test_counter", tags).Increment(); + iterations++; + + if (iterations % 500000 == 0) + { + if (elapsed() > max_duration_seconds) + { + break; + } + } + } + + double total_elapsed = elapsed(); + double rate_per_second = iterations / total_elapsed; + + std::cout << "Buffering enabled: " << (bufferingEnabled ? "Yes" : "No") << std::endl; + std::cout << "Iterations completed: " << iterations << std::endl; + std::cout << "Total elapsed time: " << std::fixed << std::setprecision(2) << total_elapsed << " seconds" << std::endl; + std::cout << "Rate: " << std::fixed << std::setprecision(2) << rate_per_second << " iterations/second" << std::endl; + return 0; +} \ No newline at end of file diff --git a/spectator/registry.cpp b/spectator/registry.cpp index 1b3c700..a1f171e 100644 --- a/spectator/registry.cpp +++ b/spectator/registry.cpp @@ -3,7 +3,6 @@ std::pair ParseUdpAddress(const std::string& address) { - std::regex pattern("udp://([0-9.]+):(\\d+)"); std::smatch matches; @@ -22,6 +21,19 @@ std::pair ParseUdpAddress(const std::string& address) return {ip, port}; } +std::string ParseUnixAddress(const std::string& address) +{ + std::regex pattern("unix://(.*)"); + std::smatch matches; + + if (!std::regex_match(address, matches, pattern) || matches.size() != 2) + { + throw std::runtime_error("Invalid Unix address format"); + } + + return matches[1].str(); +} + Registry::Registry(const Config& config) : m_config(config) { if (config.GetWriterType() == WriterType::Memory) @@ -33,13 +45,13 @@ Registry::Registry(const Config& config) : m_config(config) { auto [ip, port] = ParseUdpAddress(this->m_config.GetWriterLocation()); Logger::info("Registry initializing UDP Writer at {}:{}", ip, port); - Writer::Initialize(config.GetWriterType(), ip, port); - + Writer::Initialize(config.GetWriterType(), ip, port, this->m_config.GetWriterBufferSize()); } else if (config.GetWriterType() == WriterType::Unix) { + auto socketPath = ParseUnixAddress(this->m_config.GetWriterLocation()); Logger::info("Registry initializing UDS Writer at {null}:{null}"); - //Writer::Initialize(config.GetWriterType()); + Writer::Initialize(config.GetWriterType(), socketPath, 0, this->m_config.GetWriterBufferSize()); } } From 43fcde7f61249ae6cbc45c45ee17490aeba4ccb4 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Thu, 19 Jun 2025 12:26:34 -0500 Subject: [PATCH 22/34] improve line construction for meters --- libs/meter/meter_types/include/age_gauge.h | 5 ++--- libs/meter/meter_types/include/counter.h | 3 +-- libs/meter/meter_types/include/dist_summary.h | 3 +-- libs/meter/meter_types/include/gauge.h | 3 +-- libs/meter/meter_types/include/max_gauge.h | 3 +-- libs/meter/meter_types/include/meter.h | 19 +++++++++++++++++++ .../meter_types/include/monotonic_counter.h | 3 +-- .../include/monotonic_counter_uint.h | 3 +-- .../include/percentile_dist_summary.h | 3 +-- .../meter_types/include/percentile_timer.h | 3 +-- libs/meter/meter_types/include/timer.h | 3 +-- 11 files changed, 30 insertions(+), 21 deletions(-) diff --git a/libs/meter/meter_types/include/age_gauge.h b/libs/meter/meter_types/include/age_gauge.h index b84647a..d6f64fd 100644 --- a/libs/meter/meter_types/include/age_gauge.h +++ b/libs/meter/meter_types/include/age_gauge.h @@ -15,14 +15,13 @@ class AgeGauge final : public Meter void Now() { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + "0"; + auto line = this->ConstructLine(0); Writer::GetInstance().Write(line); } void Set(const int& seconds) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + - std::to_string(seconds); + auto line = this->ConstructLine(seconds); Writer::GetInstance().Write(line); } }; diff --git a/libs/meter/meter_types/include/counter.h b/libs/meter/meter_types/include/counter.h index 0105f26..49b2f8a 100644 --- a/libs/meter/meter_types/include/counter.h +++ b/libs/meter/meter_types/include/counter.h @@ -17,8 +17,7 @@ class Counter final : public Meter { if (delta > 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + - std::to_string(delta); + auto line = this->ConstructLine(delta); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/dist_summary.h b/libs/meter/meter_types/include/dist_summary.h index 6180307..aaa9981 100644 --- a/libs/meter/meter_types/include/dist_summary.h +++ b/libs/meter/meter_types/include/dist_summary.h @@ -17,8 +17,7 @@ class DistributionSummary final : public Meter { if (amount >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + - std::to_string(amount); + auto line = this->ConstructLine(amount); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/gauge.h b/libs/meter/meter_types/include/gauge.h index d135dca..d51ad76 100644 --- a/libs/meter/meter_types/include/gauge.h +++ b/libs/meter/meter_types/include/gauge.h @@ -21,8 +21,7 @@ class Gauge final : public Meter void Set(const double& value) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + - std::to_string(value); + auto line = this->ConstructLine(value); Writer::GetInstance().Write(line); } }; \ No newline at end of file diff --git a/libs/meter/meter_types/include/max_gauge.h b/libs/meter/meter_types/include/max_gauge.h index 61ea1bd..b741caa 100644 --- a/libs/meter/meter_types/include/max_gauge.h +++ b/libs/meter/meter_types/include/max_gauge.h @@ -15,8 +15,7 @@ class MaxGauge final : public Meter void Set(const double& value) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + - std::to_string(value); + auto line = this->ConstructLine(value); Writer::GetInstance().Write(line); } }; \ No newline at end of file diff --git a/libs/meter/meter_types/include/meter.h b/libs/meter/meter_types/include/meter.h index 86a0317..1f102b0 100644 --- a/libs/meter/meter_types/include/meter.h +++ b/libs/meter/meter_types/include/meter.h @@ -17,6 +17,25 @@ class Meter const MeterId& GetId() const noexcept { return m_id; } const std::string& GetMeterTypeSymbol() const noexcept { return m_meterTypeSymbol; } + + template + inline std::string ConstructLine(const T& value) const + { + // Pre-calculate the required size to avoid reallocations + const auto& id_str = m_id.GetSpectatordId(); + const auto value_str = std::to_string(value); + std::string result; + result.reserve(m_meterTypeSymbol.size() + id_str.size() + value_str.size() + 2); // +2 for two separators + + // Build the string with append operations (more efficient than + operator) + result.append(m_meterTypeSymbol); + result.append(FIELD_SEPARATOR); + result.append(id_str); + result.append(FIELD_SEPARATOR); + result.append(value_str); + + return result; + } protected: MeterId m_id; diff --git a/libs/meter/meter_types/include/monotonic_counter.h b/libs/meter/meter_types/include/monotonic_counter.h index c5f72e2..51751db 100644 --- a/libs/meter/meter_types/include/monotonic_counter.h +++ b/libs/meter/meter_types/include/monotonic_counter.h @@ -15,8 +15,7 @@ class MonotonicCounter final : public Meter void Set(const double& amount) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + - std::to_string(amount); + auto line = this->ConstructLine(amount); Writer::GetInstance().Write(line); } }; diff --git a/libs/meter/meter_types/include/monotonic_counter_uint.h b/libs/meter/meter_types/include/monotonic_counter_uint.h index 79aad7a..e761603 100644 --- a/libs/meter/meter_types/include/monotonic_counter_uint.h +++ b/libs/meter/meter_types/include/monotonic_counter_uint.h @@ -15,8 +15,7 @@ class MonotonicCounterUint final : public Meter void Set(const uint64_t& amount) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + - std::to_string(amount); + auto line = this->ConstructLine(amount); Writer::GetInstance().Write(line); } }; diff --git a/libs/meter/meter_types/include/percentile_dist_summary.h b/libs/meter/meter_types/include/percentile_dist_summary.h index 87b52ba..da4bb2b 100644 --- a/libs/meter/meter_types/include/percentile_dist_summary.h +++ b/libs/meter/meter_types/include/percentile_dist_summary.h @@ -20,8 +20,7 @@ class PercentileDistributionSummary final : public Meter { if (amount >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + - std::to_string(amount); + auto line = this->ConstructLine(amount); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/percentile_timer.h b/libs/meter/meter_types/include/percentile_timer.h index 037bad5..e05da8e 100644 --- a/libs/meter/meter_types/include/percentile_timer.h +++ b/libs/meter/meter_types/include/percentile_timer.h @@ -17,8 +17,7 @@ class PercentileTimer final : public Meter { if (seconds >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + - std::to_string(seconds); + auto line = this->ConstructLine(seconds); Writer::GetInstance().Write(line); } } diff --git a/libs/meter/meter_types/include/timer.h b/libs/meter/meter_types/include/timer.h index 8dccdfd..5ead1a3 100644 --- a/libs/meter/meter_types/include/timer.h +++ b/libs/meter/meter_types/include/timer.h @@ -17,8 +17,7 @@ class Timer final : public Meter { if (seconds >= 0) { - auto line = this->m_meterTypeSymbol + FIELD_SEPARATOR + this->m_id.GetSpectatordId() + FIELD_SEPARATOR + - std::to_string(seconds); + auto line = this->ConstructLine(seconds); Writer::GetInstance().Write(line); } } From e12c6319c3016fea7bd67020f5e75260dc34bbd0 Mon Sep 17 00:00:00 2001 From: ecbadeaux Date: Thu, 19 Jun 2025 19:19:34 +0000 Subject: [PATCH 23/34] update performnace tests --- libs/logger/logger.h | 2 +- libs/writer/writer_types/include/uds_writer.h | 3 +- libs/writer/writer_types/src/uds_writer.cpp | 16 +-- .../test_utils/uds_server/uds_server.cpp | 127 ++++++++--------- performance_tests/CMakeLists.txt | 7 +- performance_tests/performance_test.cpp | 129 ++++++++++++++++++ performance_tests/udp_test.cpp | 77 ----------- performance_tests/uds_test.cpp | 77 ----------- 8 files changed, 199 insertions(+), 239 deletions(-) create mode 100644 performance_tests/performance_test.cpp delete mode 100644 performance_tests/udp_test.cpp delete mode 100644 performance_tests/uds_test.cpp diff --git a/libs/logger/logger.h b/libs/logger/logger.h index f68e8c5..3eb9ed6 100644 --- a/libs/logger/logger.h +++ b/libs/logger/logger.h @@ -92,4 +92,4 @@ class Logger final : public Singleton { if (s_loggingEnabled) GetLogger()->error(fmt, std::forward(args)...); } -}; \ No newline at end of file +}; diff --git a/libs/writer/writer_types/include/uds_writer.h b/libs/writer/writer_types/include/uds_writer.h index 5707577..22adac3 100644 --- a/libs/writer/writer_types/include/uds_writer.h +++ b/libs/writer/writer_types/include/uds_writer.h @@ -17,7 +17,8 @@ class UDSWriter final : public BaseWriter private: std::string m_socketPath; std::unique_ptr m_ioContext; - std::unique_ptr m_socket; + std::unique_ptr m_socket; + boost::asio::local::datagram_protocol::endpoint m_endpoint; bool m_isOpen; // Helper method to initialize the connection diff --git a/libs/writer/writer_types/src/uds_writer.cpp b/libs/writer/writer_types/src/uds_writer.cpp index 07fbfa9..4dea66c 100644 --- a/libs/writer/writer_types/src/uds_writer.cpp +++ b/libs/writer/writer_types/src/uds_writer.cpp @@ -29,14 +29,15 @@ bool UDSWriter::connect() // Create a new socket if needed if (!m_socket) { - m_socket = std::make_unique(*m_ioContext); + m_socket = std::make_unique(*m_ioContext); } - // Connect to the UDS server - const local::stream_protocol::endpoint endpoint(m_socketPath); - + // Open the socket and prepare the endpoint boost::system::error_code ec; - m_socket->connect(endpoint, ec); + m_socket->open(local::datagram_protocol(), ec); + + // Set up the server endpoint + m_endpoint = local::datagram_protocol::endpoint(m_socketPath); if (ec) { @@ -67,7 +68,7 @@ void UDSWriter::Write(const std::string& message) try { boost::system::error_code ec; - boost::asio::write(*m_socket, boost::asio::buffer(message), ec); + size_t sent = m_socket->send_to(boost::asio::buffer(message), m_endpoint, 0, ec); if (ec) { @@ -76,7 +77,7 @@ void UDSWriter::Write(const std::string& message) } else { - Logger::debug("UDS Writer: Sent message ({} bytes)", message.size()); + Logger::debug("UDS Writer: Sent message ({} bytes)", sent); } } catch (const std::exception& e) @@ -93,7 +94,6 @@ void UDSWriter::Close() try { boost::system::error_code ec; - m_socket->shutdown(local::stream_protocol::socket::shutdown_both, ec); m_socket->close(ec); if (ec) diff --git a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp index b6e4342..96bd9fc 100644 --- a/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp +++ b/libs/writer/writer_types/test_utils/uds_server/uds_server.cpp @@ -1,7 +1,7 @@ #include "uds_server.h" #include #include -#include +#include #include #include #include @@ -52,92 +52,79 @@ try boost::asio::io_context io_context; - // Create and open a Unix domain socket - const boost::asio::local::stream_protocol::endpoint endpoint(socket_path); - boost::asio::local::stream_protocol::acceptor acceptor(io_context, endpoint); + // Create and open a Unix domain datagram socket + const boost::asio::local::datagram_protocol::endpoint endpoint(socket_path); + boost::asio::local::datagram_protocol::socket socket(io_context); + + boost::system::error_code ec; + socket.open(boost::asio::local::datagram_protocol(), ec); + if (ec) + { + std::cerr << "Error opening socket: " << ec.message() << std::endl; + return; + } + + socket.bind(endpoint, ec); + if (ec) + { + std::cerr << "Error binding to endpoint: " << ec.message() << std::endl; + return; + } + + // Set to non-blocking mode + socket.non_blocking(true); - std::cout << "UDS server listening on " << socket_path << std::endl; + std::cout << "UDS datagram server listening on " << socket_path << std::endl; + // Buffer for reading data + std::array buffer{}; while (uds_server_running) { - // Create a socket for the client connection - boost::asio::local::stream_protocol::socket socket(io_context); - try { - // Set acceptor to non-blocking so we can check the run flag - acceptor.non_blocking(true); - - boost::system::error_code ec; - acceptor.accept(socket, ec); - - if (ec) - { - if (ec == boost::asio::error::would_block) - { - // No connection available, wait a bit and try again - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - continue; - } - std::cerr << "Error accepting connection: " << ec.message() << std::endl; + // Client endpoint to receive the sender's address + boost::asio::local::datagram_protocol::endpoint sender_endpoint; + boost::system::error_code read_ec; + std::size_t bytes_read = 0; + + // Try to receive a datagram + bytes_read = socket.receive_from(boost::asio::buffer(buffer), sender_endpoint, 0, read_ec); + + // Handle the case where no data is available + if (read_ec == boost::asio::error::would_block) { + // No data available, wait a bit and try again + std::this_thread::sleep_for(std::chrono::milliseconds(10)); continue; } + + if (read_ec) + { + std::cerr << "Error reading from socket: " << read_ec.message() << std::endl; + continue; // Continue to next iteration instead of breaking, as each datagram is independent + } - // Connection accepted, set to non-blocking to avoid hanging - socket.non_blocking(true); - - // Buffer for reading data - std::array buffer{}; - while (uds_server_running) + if (bytes_read == buffer.size()) { - // We need to handle both data availability and potential errors - boost::system::error_code read_ec; - std::size_t bytes_read = 0; - - // Try to read data even if none is immediately available - // This allows us to detect connection closure properly - bytes_read = socket.read_some(boost::asio::buffer(buffer), read_ec); - - // Handle the case where no data is available - if (read_ec == boost::asio::error::would_block) { - // No data available, wait a bit and try again - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - continue; - } - - if (read_ec == boost::asio::error::eof) - { - // Connection closed cleanly by peer - break; - } - if (read_ec) - { - std::cerr << "Error reading from socket: " << read_ec.message() << std::endl; - break; - } - - if (bytes_read == buffer.size()) - { - std::cout << "Warning: Received data might have been truncated (buffer full)" << std::endl; - } - - // Create string from received data and store it - std::string message(buffer.data(), bytes_read); - add_uds_message(message); - auto current_messages = get_uds_messages(); - std::cout << "Received message: " << message << std::endl; - std::cout << "Total messages stored: " << current_messages.size() << std::endl; + std::cout << "Warning: Received data might have been truncated (buffer full)" << std::endl; } - // Close the connection - socket.close(); + + // Create string from received data and store it + std::string message(buffer.data(), bytes_read); + add_uds_message(message); + auto current_messages = get_uds_messages(); + std::cout << "Received datagram: " << message << std::endl; + std::cout << "Total messages stored: " << current_messages.size() << std::endl; } catch (const std::exception& e) { - std::cerr << "Exception handling client: " << e.what() << std::endl; + std::cerr << "Exception in datagram server: " << e.what() << std::endl; } } - std::cout << "UDS server shutting down..." << std::endl; + std::cout << "UDS datagram server shutting down..." << std::endl; + + // Close the socket + socket.close(); // Clean up the socket file on exit std::filesystem::remove(socket_path); diff --git a/performance_tests/CMakeLists.txt b/performance_tests/CMakeLists.txt index 95fabe8..f32acae 100644 --- a/performance_tests/CMakeLists.txt +++ b/performance_tests/CMakeLists.txt @@ -1,5 +1,2 @@ -add_executable(udp_performance_test udp_test.cpp) -target_link_libraries(udp_performance_test PRIVATE registry) - -add_executable(uds_performance_test uds_test.cpp) -target_link_libraries(uds_performance_test PRIVATE registry) \ No newline at end of file +add_executable(performance_test performance_test.cpp) +target_link_libraries(performance_test PRIVATE registry) \ No newline at end of file diff --git a/performance_tests/performance_test.cpp b/performance_tests/performance_test.cpp new file mode 100644 index 0000000..4260485 --- /dev/null +++ b/performance_tests/performance_test.cpp @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct RunTimeConfig +{ + bool bufferingEnabled; + std::string writerType; + std::string writerTypeName; + std::string counterName; + std::string locationTag; +}; + +void PrintUsage() +{ + std::cerr << "Usage: performance_test [writer_type] [buffering]" << std::endl; + std::cerr << " writer_type: udp or uds" << std::endl; + std::cerr << " buffering: 0 for disabled, 1 for enabled (default is 0)" << std::endl; +} + + +std::optional HandleArgs(int argc, char* argv[]) +{ + if (argc != 3 && argc != 2) + { + return std::nullopt; + } + + bool bufferingEnabled = false; + if (argc == 3) + { + std::string bufferingArg = argv[2]; + if (bufferingArg != "0" && bufferingArg != "1") + { + std::cerr << "Invalid buffering argument: " << bufferingArg << std::endl; + return std::nullopt; + } + bufferingEnabled = (bufferingArg == "1"); + } + + std::string writerArg = argv[1]; + if (writerArg != "udp" && writerArg != "uds") + { + std::cerr << "Invalid writer type: " << writerArg << std::endl; + return std::nullopt; + } + + RunTimeConfig config; + if (writerArg == "udp") + { + config.writerType = WriterTypes::UDP; + config.counterName = "udp_test_counter"; + config.locationTag = "udp"; + config.writerTypeName = "UDP"; + } + else + { + config.writerType = WriterTypes::Unix; + config.counterName = "unix_test_counter"; + config.locationTag = "unix"; + config.writerTypeName = "UDS"; + } + config.bufferingEnabled = bufferingEnabled; + + return config; +} + +int main(int argc, char* argv[]) +{ + auto config = HandleArgs(argc, argv); + if (config == std::nullopt) + { + PrintUsage(); + return 1; + } + + std::cout << "Running performance test with the following configuration:" << std::endl; + std::cout << "Writer Type: " << config->writerTypeName << std::endl; + std::cout << "Buffering Enabled: " << (config->bufferingEnabled ? "Yes" : "No") << std::endl; + + // Configure the registry with or without buffering based on the command line argument + auto writerConfig = WriterConfig(config->writerType); + if (config->bufferingEnabled) + { + writerConfig = WriterConfig(config->writerType, 32000); + } + auto r = Registry(Config(writerConfig)); + std::unordered_map tags = { + {"location", config->locationTag}, + {"version", "correct-horse-battery-staple"} + }; + + // Set maximum duration to 2 minutes + constexpr int max_duration_seconds = 2 * 60; + + // Track iterations and timing + unsigned long long iterations = 0; + auto start_time = std::chrono::steady_clock::now(); + double total_elapsed{}; + while (true) + { + r.counter(config->counterName, tags).Increment(); + iterations++; + + if (iterations % 500000 == 0) + { + auto now = std::chrono::steady_clock::now(); + auto elapsed = std::chrono::duration(now - start_time).count(); + if (elapsed > max_duration_seconds) + { + total_elapsed = elapsed; + break; + } + } + } + + double rate_per_second = iterations / total_elapsed; + + std::cout << "\nPerformance Test Summary:" << std::endl; + std::cout << "Iterations completed: " << iterations << std::endl; + std::cout << "Total elapsed time: " << std::fixed << std::setprecision(2) << total_elapsed << " seconds" << std::endl; + std::cout << "Rate: " << std::fixed << std::setprecision(2) << rate_per_second << " iterations/second" << std::endl; + return 0; +} diff --git a/performance_tests/udp_test.cpp b/performance_tests/udp_test.cpp deleted file mode 100644 index 6193284..0000000 --- a/performance_tests/udp_test.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char* argv[]) -{ - if (argc > 2) - { - std::cerr << "Too many arguments provided." << std::endl; - return 1; - } - - bool bufferingEnabled = false; - - // If argument is provided and equals 1, enable buffering - if (argc == 2) { - if (std::string(argv[1]) == "1") { - bufferingEnabled = true; - } else { - std::cerr << "Usage: " << argv[0] << " [1]" << std::endl; - std::cerr << " No argument: Run without buffering" << std::endl; - std::cerr << " 1: Run with buffering enabled" << std::endl; - return 1; - } - } - // No arguments means bufferingEnabled remains false - Logger::info("Starting UDP performance test with buffering {}", bufferingEnabled ? "enabled" : "disabled"); - - // Configure the registry with or without buffering based on the command line argument - auto writerConfig = WriterConfig(WriterTypes::UDP); - if (bufferingEnabled) - { - writerConfig = WriterConfig(WriterTypes::UDP, 4096); - } - auto r = Registry(Config(writerConfig)); - std::unordered_map tags = { {"location", "udp"}, {"version", "correct-horse-battery-staple"}}; - - // Set maximum duration to 2 minutes - constexpr int max_duration_seconds = 2 * 60; - - // Track iterations and timing - unsigned long long iterations = 0; - auto start_time = std::chrono::steady_clock::now(); - - // Helper function to get elapsed time in seconds - auto elapsed = [&start_time]() -> double { - auto now = std::chrono::steady_clock::now(); - return std::chrono::duration(now - start_time).count(); - }; - - while (true) - { - r.counter("udp_test_counter", tags).Increment(); - iterations++; - - if (iterations % 500000 == 0) - { - if (elapsed() > max_duration_seconds) - { - break; - } - } - } - - double total_elapsed = elapsed(); - double rate_per_second = iterations / total_elapsed; - - std::cout << "Buffering enabled: " << (bufferingEnabled ? "Yes" : "No") << std::endl; - std::cout << "Iterations completed: " << iterations << std::endl; - std::cout << "Total elapsed time: " << std::fixed << std::setprecision(2) << total_elapsed << " seconds" << std::endl; - std::cout << "Rate: " << std::fixed << std::setprecision(2) << rate_per_second << " iterations/second" << std::endl; - return 0; -} \ No newline at end of file diff --git a/performance_tests/uds_test.cpp b/performance_tests/uds_test.cpp deleted file mode 100644 index a9f7a36..0000000 --- a/performance_tests/uds_test.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -int main(int argc, char* argv[]) -{ - if (argc > 2) - { - std::cerr << "Too many arguments provided." << std::endl; - return 1; - } - - bool bufferingEnabled = false; - - // If argument is provided and equals 1, enable buffering - if (argc == 2) { - if (std::string(argv[1]) == "1") { - bufferingEnabled = true; - } else { - std::cerr << "Usage: " << argv[0] << " [1]" << std::endl; - std::cerr << " No argument: Run without buffering" << std::endl; - std::cerr << " 1: Run with buffering enabled" << std::endl; - return 1; - } - } - // No arguments means bufferingEnabled remains false - Logger::info("Starting UDP performance test with buffering {}", bufferingEnabled ? "enabled" : "disabled"); - - // Configure the registry with or without buffering based on the command line argument - auto writerConfig = WriterConfig(WriterTypes::Unix); - if (bufferingEnabled) - { - writerConfig = WriterConfig(WriterTypes::Unix, 4096); - } - auto r = Registry(Config(writerConfig)); - std::unordered_map tags = { {"location", "unix"}, {"version", "correct-horse-battery-staple"}}; - - // Set maximum duration to 2 minutes - constexpr int max_duration_seconds = 2 * 60; - - // Track iterations and timing - unsigned long long iterations = 0; - auto start_time = std::chrono::steady_clock::now(); - - // Helper function to get elapsed time in seconds - auto elapsed = [&start_time]() -> double { - auto now = std::chrono::steady_clock::now(); - return std::chrono::duration(now - start_time).count(); - }; - - while (true) - { - r.counter("unix_test_counter", tags).Increment(); - iterations++; - - if (iterations % 500000 == 0) - { - if (elapsed() > max_duration_seconds) - { - break; - } - } - } - - double total_elapsed = elapsed(); - double rate_per_second = iterations / total_elapsed; - - std::cout << "Buffering enabled: " << (bufferingEnabled ? "Yes" : "No") << std::endl; - std::cout << "Iterations completed: " << iterations << std::endl; - std::cout << "Total elapsed time: " << std::fixed << std::setprecision(2) << total_elapsed << " seconds" << std::endl; - std::cout << "Rate: " << std::fixed << std::setprecision(2) << rate_per_second << " iterations/second" << std::endl; - return 0; -} \ No newline at end of file From 9d396893f2a8eef5924c0eb816a46c18b7c03e15 Mon Sep 17 00:00:00 2001 From: ecbadeaux Date: Thu, 19 Jun 2025 19:47:02 +0000 Subject: [PATCH 24/34] add threading performance test --- performance_tests/performance_test.cpp | 69 ++++++++++++++++++++------ 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/performance_tests/performance_test.cpp b/performance_tests/performance_test.cpp index 4260485..40351aa 100644 --- a/performance_tests/performance_test.cpp +++ b/performance_tests/performance_test.cpp @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include struct RunTimeConfig { @@ -23,7 +26,6 @@ void PrintUsage() std::cerr << " buffering: 0 for disabled, 1 for enabled (default is 0)" << std::endl; } - std::optional HandleArgs(int argc, char* argv[]) { if (argc != 3 && argc != 2) @@ -87,7 +89,7 @@ int main(int argc, char* argv[]) auto writerConfig = WriterConfig(config->writerType); if (config->bufferingEnabled) { - writerConfig = WriterConfig(config->writerType, 32000); + writerConfig = WriterConfig(config->writerType, 4096); } auto r = Registry(Config(writerConfig)); std::unordered_map tags = { @@ -98,32 +100,67 @@ int main(int argc, char* argv[]) // Set maximum duration to 2 minutes constexpr int max_duration_seconds = 2 * 60; - // Track iterations and timing - unsigned long long iterations = 0; + // Track iterations and timing with atomic counter for thread safety + std::atomic iterations{0}; auto start_time = std::chrono::steady_clock::now(); double total_elapsed{}; - while (true) + + unsigned int num_threads = 4; + num_threads = std::max(1u, std::min(16u, num_threads)); + + std::cout << "Running performance test with " << num_threads << " threads..." << std::endl; + + // Flag to signal threads to stop + std::atomic should_stop{false}; + + // Thread function + auto thread_func = [&r, &config, &tags, &iterations, &should_stop]() + { + while (should_stop == false) + { + r.counter(config->counterName, tags).Increment(); + iterations.fetch_add(1, std::memory_order_relaxed); + } + }; + + // Create and start threads + std::vector threads; + for (unsigned int i = 0; i < num_threads; ++i) { - r.counter(config->counterName, tags).Increment(); - iterations++; + threads.emplace_back(thread_func); + } + + // Monitor progress + while (true) + { + std::this_thread::sleep_for(std::chrono::seconds(6)); + auto now = std::chrono::steady_clock::now(); + auto elapsed = std::chrono::duration(now - start_time).count(); - if (iterations % 500000 == 0) + if (elapsed > max_duration_seconds) + { + total_elapsed = elapsed; + should_stop = true; + break; + } + } + + // Wait for all threads to finish + for (auto& t : threads) + { + if (t.joinable()) { - auto now = std::chrono::steady_clock::now(); - auto elapsed = std::chrono::duration(now - start_time).count(); - if (elapsed > max_duration_seconds) - { - total_elapsed = elapsed; - break; - } + t.join(); } } - double rate_per_second = iterations / total_elapsed; + double rate_per_second = static_cast(iterations) / total_elapsed; std::cout << "\nPerformance Test Summary:" << std::endl; + std::cout << "Threads used: " << num_threads << std::endl; std::cout << "Iterations completed: " << iterations << std::endl; std::cout << "Total elapsed time: " << std::fixed << std::setprecision(2) << total_elapsed << " seconds" << std::endl; std::cout << "Rate: " << std::fixed << std::setprecision(2) << rate_per_second << " iterations/second" << std::endl; + std::cout << "Rate per thread: " << std::fixed << std::setprecision(2) << rate_per_second / num_threads << " iterations/second/thread" << std::endl; return 0; } From 42be0f4161d4793700268472099d09e76c1ba18a Mon Sep 17 00:00:00 2001 From: ecbadeaux Date: Thu, 19 Jun 2025 22:27:08 +0000 Subject: [PATCH 25/34] fix whitepsace check in tags --- libs/config/config.cpp | 22 +++++++++++++++++++--- libs/config/test_config.cpp | 13 +++++++++++++ libs/meter/meter_id/meter_id.cpp | 8 ++++++-- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/libs/config/config.cpp b/libs/config/config.cpp index ca780f6..9fc39b1 100644 --- a/libs/config/config.cpp +++ b/libs/config/config.cpp @@ -1,4 +1,6 @@ #include +#include +#include struct ConfigConstants { @@ -8,6 +10,11 @@ struct ConfigConstants static constexpr auto envVarProcess = "TITUS_PROCESS_NAME"; }; +bool IsEmptyOrWhitespace(const std::string& str) +{ + return str.empty() || std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isspace(c); }); +} + std::unordered_map CalculateTags( const std::unordered_map& tags) { @@ -15,19 +22,28 @@ std::unordered_map CalculateTags( const char* container_name = std::getenv(ConfigConstants::envVarContainer); const char* process_name = std::getenv(ConfigConstants::envVarProcess); + if (container_name != nullptr) { - valid_tags[ConfigConstants::container] = container_name; + std::string container_str(container_name); + if (IsEmptyOrWhitespace(container_str) == false) + { + valid_tags[ConfigConstants::container] = container_str; + } } if (process_name != nullptr) { - valid_tags[ConfigConstants::process] = process_name; + std::string process_str(process_name); + if (IsEmptyOrWhitespace(process_str) == false) + { + valid_tags[ConfigConstants::process] = process_str; + } } for (const auto& [fst, snd] : tags) { - if (fst.empty() == false && snd.empty() == false) + if (IsEmptyOrWhitespace(fst) == false && IsEmptyOrWhitespace(snd) == false) { valid_tags[fst] = snd; } diff --git a/libs/config/test_config.cpp b/libs/config/test_config.cpp index 065c614..716adf1 100644 --- a/libs/config/test_config.cpp +++ b/libs/config/test_config.cpp @@ -202,4 +202,17 @@ TEST_F(ConfigTest, MergingTags) EXPECT_EQ(config.GetExtraTags().size(), 1); EXPECT_EQ(config.GetExtraTags().at("nf.container"), "override-container"); } + + { + containerGuard.setValue(" "); + processGuard.setValue(""); + + std::unordered_map tags = {{"custom", "value"}, {"env", "test"}}; + + Config config(writerConfig, tags); + + EXPECT_EQ(config.GetExtraTags().size(), 2); + EXPECT_EQ(config.GetExtraTags().at("custom"), "value"); + EXPECT_EQ(config.GetExtraTags().at("env"), "test"); + } } \ No newline at end of file diff --git a/libs/meter/meter_id/meter_id.cpp b/libs/meter/meter_id/meter_id.cpp index 6de5f92..f2c7094 100644 --- a/libs/meter/meter_id/meter_id.cpp +++ b/libs/meter/meter_id/meter_id.cpp @@ -6,18 +6,22 @@ // Define the static member const std::regex INVALID_CHARS("[^-._A-Za-z0-9~^]"); +bool IsEmptyOrWhitespace(const std::string& str) +{ + return str.empty() || std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isspace(c); }); +} + std::unordered_map ValidateTags(const std::unordered_map& tags) { std::unordered_map validTags{}; for (const auto& [key, value] : tags) { - if (key.empty() == false && value.empty() == false) + if (IsEmptyOrWhitespace(key) == false && IsEmptyOrWhitespace(value) == false) { validTags[key] = value; } } - return validTags; } From 823be6829165d168b55c4b61b7881a1374a831f8 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Sat, 21 Jun 2025 17:33:41 -0500 Subject: [PATCH 26/34] remove duplicate function --- libs/config/CMakeLists.txt | 2 ++ libs/config/config.cpp | 23 ++++++++++++++++----- libs/logger/logger.h | 2 +- libs/meter/meter_id/CMakeLists.txt | 5 +++++ libs/meter/meter_id/meter_id.cpp | 6 +----- libs/utils/include/util.h | 4 +++- libs/utils/src/util.cpp | 5 +++++ libs/writer/writer_config/writer_config.cpp | 8 +++---- 8 files changed, 39 insertions(+), 16 deletions(-) diff --git a/libs/config/CMakeLists.txt b/libs/config/CMakeLists.txt index ad90c6b..f324ef3 100644 --- a/libs/config/CMakeLists.txt +++ b/libs/config/CMakeLists.txt @@ -8,7 +8,9 @@ target_include_directories(spectator-config target_link_libraries(spectator-config PUBLIC + spectator-logger spectator-writer-config + spectator-utils ) add_executable(config-tests diff --git a/libs/config/config.cpp b/libs/config/config.cpp index 9fc39b1..3f16412 100644 --- a/libs/config/config.cpp +++ b/libs/config/config.cpp @@ -1,4 +1,9 @@ #include + +#include +#include +#include + #include #include @@ -10,11 +15,6 @@ struct ConfigConstants static constexpr auto envVarProcess = "TITUS_PROCESS_NAME"; }; -bool IsEmptyOrWhitespace(const std::string& str) -{ - return str.empty() || std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isspace(c); }); -} - std::unordered_map CalculateTags( const std::unordered_map& tags) { @@ -55,4 +55,17 @@ std::unordered_map CalculateTags( Config::Config(const WriterConfig& writerConfig, const std::unordered_map& extraTags) : m_extraTags(CalculateTags(extraTags)), m_writerConfig(writerConfig) { + Logger::info("Config initialized with writer type: {}, buffer size: {}, location: {}", + WriterTypeToString(m_writerConfig.GetType()), m_writerConfig.GetBufferSize(), m_writerConfig.GetLocation()); + if (m_extraTags.empty() == true) + { + Logger::info("Config initialized with no extra tags provided."); + return; + } + + Logger::info("Config initialized with the following extra tags:"); + for (const auto& [key, value] : m_extraTags) + { + Logger::info(" {}: {}", key, value); + } } diff --git a/libs/logger/logger.h b/libs/logger/logger.h index 3eb9ed6..5450ecc 100644 --- a/libs/logger/logger.h +++ b/libs/logger/logger.h @@ -17,7 +17,7 @@ class Logger final : public Singleton { private: spdlog::logger* m_logger; // Use raw pointer, not unique_ptr - inline static bool s_loggingEnabled = false; // Static flag to control logging (C++17 inline initialization) + inline static bool s_loggingEnabled = true; // Static flag to control logging (C++17 inline initialization) friend class Singleton; diff --git a/libs/meter/meter_id/CMakeLists.txt b/libs/meter/meter_id/CMakeLists.txt index 803c03e..52dcbc6 100644 --- a/libs/meter/meter_id/CMakeLists.txt +++ b/libs/meter/meter_id/CMakeLists.txt @@ -7,6 +7,11 @@ target_include_directories(spectator-meter-id ${CMAKE_SOURCE_DIR} ) +target_link_libraries(spectator-meter-id + PUBLIC + spectator-utils +) + add_executable(MeterID-test test_meter_id.cpp ) diff --git a/libs/meter/meter_id/meter_id.cpp b/libs/meter/meter_id/meter_id.cpp index f2c7094..cd7ba48 100644 --- a/libs/meter/meter_id/meter_id.cpp +++ b/libs/meter/meter_id/meter_id.cpp @@ -1,16 +1,12 @@ #include +#include #include #include // Define the static member const std::regex INVALID_CHARS("[^-._A-Za-z0-9~^]"); -bool IsEmptyOrWhitespace(const std::string& str) -{ - return str.empty() || std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isspace(c); }); -} - std::unordered_map ValidateTags(const std::unordered_map& tags) { std::unordered_map validTags{}; diff --git a/libs/utils/include/util.h b/libs/utils/include/util.h index b778285..b320327 100644 --- a/libs/utils/include/util.h +++ b/libs/utils/include/util.h @@ -50,4 +50,6 @@ struct ProtocolLine } }; -std::optional ParseProtocolLine(const std::string& line); \ No newline at end of file +std::optional ParseProtocolLine(const std::string& line); + +bool IsEmptyOrWhitespace(const std::string& str); \ No newline at end of file diff --git a/libs/utils/src/util.cpp b/libs/utils/src/util.cpp index e891e38..6e482f1 100644 --- a/libs/utils/src/util.cpp +++ b/libs/utils/src/util.cpp @@ -54,4 +54,9 @@ std::optional ParseProtocolLine(const std::string& line) // The last part is the value value = mainParts[2]; return ProtocolLine{symbol, MeterId{name, tags}, value}; +} + +bool IsEmptyOrWhitespace(const std::string& str) +{ + return str.empty() || std::all_of(str.begin(), str.end(), [](unsigned char c) { return std::isspace(c); }); } \ No newline at end of file diff --git a/libs/writer/writer_config/writer_config.cpp b/libs/writer/writer_config/writer_config.cpp index 1fd4ce0..d1936a0 100644 --- a/libs/writer/writer_config/writer_config.cpp +++ b/libs/writer/writer_config/writer_config.cpp @@ -32,7 +32,7 @@ WriterConfig::WriterConfig(const std::string& type) { if (const char* envLocation = std::getenv("SPECTATOR_OUTPUT_LOCATION"); envLocation != nullptr) { - Logger::debug("Using environment variable SPECTATOR_OUTPUT_LOCATION: {}", envLocation); + Logger::info("Environment variable set, SPECTATOR_OUTPUT_LOCATION: {}", envLocation); const std::string envValue(envLocation); auto [writer_type, location] = GetWriterConfigFromString(envValue); m_type = writer_type; @@ -40,12 +40,11 @@ WriterConfig::WriterConfig(const std::string& type) } else { - Logger::debug("Using provided type: {}", type); auto [writer_type, location] = GetWriterConfigFromString(type); m_type = writer_type; m_location = location; } - Logger::debug("WriterConfig initialized with type: {}, location: {}", WriterTypeToString(m_type), m_location); + Logger::info("WriterConfig initialized with type: {}, location: {}", WriterTypeToString(m_type), m_location); } WriterConfig::WriterConfig(const std::string& type, const unsigned int bufferSize) @@ -53,5 +52,6 @@ WriterConfig::WriterConfig(const std::string& type, const unsigned int bufferSiz { m_bufferSize = bufferSize; m_isBufferingEnabled = true; - Logger::debug("WriterConfig buffering enabled with size: {}", m_bufferSize); + Logger::info("WriterConfig buffering enabled with size: {}", m_bufferSize); + } \ No newline at end of file From 1f7a1b65260c82a20dfafcfe374f4dd9b8fef3cd Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Thu, 26 Jun 2025 12:35:08 -0500 Subject: [PATCH 27/34] Changes required while modifying atlas --- libs/meter/meter_id/meter_id.cpp | 5 ++++ libs/meter/meter_id/meter_id.h | 2 ++ libs/meter/meter_types/include/age_gauge.h | 4 +-- libs/meter/meter_types/include/counter.h | 2 +- libs/meter/meter_types/include/dist_summary.h | 2 +- libs/meter/meter_types/include/gauge.h | 2 +- libs/meter/meter_types/include/max_gauge.h | 2 +- .../meter_types/include/monotonic_counter.h | 2 +- .../include/monotonic_counter_uint.h | 2 +- .../include/percentile_dist_summary.h | 2 +- .../meter_types/include/percentile_timer.h | 2 +- libs/meter/meter_types/include/timer.h | 2 +- spectator/CMakeLists.txt | 30 ++++++++++++++----- 13 files changed, 41 insertions(+), 18 deletions(-) diff --git a/libs/meter/meter_id/meter_id.cpp b/libs/meter/meter_id/meter_id.cpp index cd7ba48..179b2be 100644 --- a/libs/meter/meter_id/meter_id.cpp +++ b/libs/meter/meter_id/meter_id.cpp @@ -60,6 +60,11 @@ MeterId MeterId::WithTags(const std::unordered_map& ad return MeterId(m_name, new_tags); } +MeterId MeterId::WithStat(const std::string& stat) const +{ + return WithTag("statistic", stat); +} + bool MeterId::operator==(const MeterId& other) const { return m_name == other.m_name && m_tags == other.m_tags; } std::string MeterId::to_string() const diff --git a/libs/meter/meter_id/meter_id.h b/libs/meter/meter_id/meter_id.h index d546abf..1427c9c 100644 --- a/libs/meter/meter_id/meter_id.h +++ b/libs/meter/meter_id/meter_id.h @@ -19,6 +19,8 @@ class MeterId MeterId WithTags(const std::unordered_map& additional_tags) const; + MeterId WithStat(const std::string& stat) const; + bool operator==(const MeterId& other) const; std::string to_string() const; diff --git a/libs/meter/meter_types/include/age_gauge.h b/libs/meter/meter_types/include/age_gauge.h index d6f64fd..1ee7f54 100644 --- a/libs/meter/meter_types/include/age_gauge.h +++ b/libs/meter/meter_types/include/age_gauge.h @@ -13,13 +13,13 @@ class AgeGauge final : public Meter public: explicit AgeGauge(const MeterId& meter_id) : Meter(meter_id, AGE_GAUGE_TYPE_SYMBOL) {} - void Now() + void Now() const { auto line = this->ConstructLine(0); Writer::GetInstance().Write(line); } - void Set(const int& seconds) + void Set(const int& seconds) const { auto line = this->ConstructLine(seconds); Writer::GetInstance().Write(line); diff --git a/libs/meter/meter_types/include/counter.h b/libs/meter/meter_types/include/counter.h index 49b2f8a..1df957f 100644 --- a/libs/meter/meter_types/include/counter.h +++ b/libs/meter/meter_types/include/counter.h @@ -13,7 +13,7 @@ class Counter final : public Meter public: explicit Counter(const MeterId& meter_id) : Meter(meter_id, COUNTER_TYPE_SYMBOL) {} - void Increment(const double& delta = 1) + void Increment(const double& delta = 1) const { if (delta > 0) { diff --git a/libs/meter/meter_types/include/dist_summary.h b/libs/meter/meter_types/include/dist_summary.h index aaa9981..00f56f7 100644 --- a/libs/meter/meter_types/include/dist_summary.h +++ b/libs/meter/meter_types/include/dist_summary.h @@ -13,7 +13,7 @@ class DistributionSummary final : public Meter public: explicit DistributionSummary(const MeterId& meter_id) : Meter(meter_id, DisTRIBUTION_SUMMARY_TYPE_SYMBOL) {} - void Record(const int& amount) + void Record(const int& amount) const { if (amount >= 0) { diff --git a/libs/meter/meter_types/include/gauge.h b/libs/meter/meter_types/include/gauge.h index d51ad76..efb839e 100644 --- a/libs/meter/meter_types/include/gauge.h +++ b/libs/meter/meter_types/include/gauge.h @@ -19,7 +19,7 @@ class Gauge final : public Meter { } - void Set(const double& value) + void Set(const double& value) const { auto line = this->ConstructLine(value); Writer::GetInstance().Write(line); diff --git a/libs/meter/meter_types/include/max_gauge.h b/libs/meter/meter_types/include/max_gauge.h index b741caa..8ee514b 100644 --- a/libs/meter/meter_types/include/max_gauge.h +++ b/libs/meter/meter_types/include/max_gauge.h @@ -13,7 +13,7 @@ class MaxGauge final : public Meter public: explicit MaxGauge(const MeterId& meter_id) : Meter(meter_id, MAX_GAUGE_TYPE_SYMBOL) {} - void Set(const double& value) + void Set(const double& value) const { auto line = this->ConstructLine(value); Writer::GetInstance().Write(line); diff --git a/libs/meter/meter_types/include/monotonic_counter.h b/libs/meter/meter_types/include/monotonic_counter.h index 51751db..689bdf8 100644 --- a/libs/meter/meter_types/include/monotonic_counter.h +++ b/libs/meter/meter_types/include/monotonic_counter.h @@ -13,7 +13,7 @@ class MonotonicCounter final : public Meter public: explicit MonotonicCounter(const MeterId& meter_id) : Meter(meter_id, MONOTONIC_COUNTER_TYPE_SYMBOL) {} - void Set(const double& amount) + void Set(const double& amount) const { auto line = this->ConstructLine(amount); Writer::GetInstance().Write(line); diff --git a/libs/meter/meter_types/include/monotonic_counter_uint.h b/libs/meter/meter_types/include/monotonic_counter_uint.h index e761603..db056a9 100644 --- a/libs/meter/meter_types/include/monotonic_counter_uint.h +++ b/libs/meter/meter_types/include/monotonic_counter_uint.h @@ -13,7 +13,7 @@ class MonotonicCounterUint final : public Meter public: explicit MonotonicCounterUint(const MeterId& meter_id) : Meter(meter_id, MONOTONIC_COUNTER_UINT_TYPE_SYMBOL) {} - void Set(const uint64_t& amount) + void Set(const uint64_t& amount) const { auto line = this->ConstructLine(amount); Writer::GetInstance().Write(line); diff --git a/libs/meter/meter_types/include/percentile_dist_summary.h b/libs/meter/meter_types/include/percentile_dist_summary.h index da4bb2b..5f53599 100644 --- a/libs/meter/meter_types/include/percentile_dist_summary.h +++ b/libs/meter/meter_types/include/percentile_dist_summary.h @@ -16,7 +16,7 @@ class PercentileDistributionSummary final : public Meter { } - void Record(const int& amount) + void Record(const int& amount) const { if (amount >= 0) { diff --git a/libs/meter/meter_types/include/percentile_timer.h b/libs/meter/meter_types/include/percentile_timer.h index e05da8e..7a8ae77 100644 --- a/libs/meter/meter_types/include/percentile_timer.h +++ b/libs/meter/meter_types/include/percentile_timer.h @@ -13,7 +13,7 @@ class PercentileTimer final : public Meter public: explicit PercentileTimer(const MeterId& meter_id) : Meter(meter_id, PERCENTILE_TIMER_TYPE_SYMBOL) {} - void Record(const double& seconds) + void Record(const double& seconds) const { if (seconds >= 0) { diff --git a/libs/meter/meter_types/include/timer.h b/libs/meter/meter_types/include/timer.h index 5ead1a3..f049182 100644 --- a/libs/meter/meter_types/include/timer.h +++ b/libs/meter/meter_types/include/timer.h @@ -13,7 +13,7 @@ class Timer final : public Meter public: explicit Timer(const MeterId& meter_id) : Meter(meter_id, TIMER_TYPE_SYMBOL) {} - void Record(const double& seconds) + void Record(const double& seconds) const { if (seconds >= 0) { diff --git a/spectator/CMakeLists.txt b/spectator/CMakeLists.txt index c9ca3e6..b3539be 100644 --- a/spectator/CMakeLists.txt +++ b/spectator/CMakeLists.txt @@ -1,18 +1,34 @@ +# Create a monolithic registry library with all required sources add_library(registry registry.cpp + # Include all required source files directly + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/config/config.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/meter/meter_id/meter_id.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/utils/src/util.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/writer/writer_config/writer_config.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/writer/writer_types/src/memory_writer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/writer/writer_types/src/udp_writer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/writer/writer_types/src/uds_writer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/writer/writer_wrapper/writer.cpp ) + target_include_directories(registry PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/config + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/meter/meter_id + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/meter/meter_types/include + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/utils/include + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/writer/writer_config + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/writer/writer_types/include + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/writer/writer_wrapper + ${CMAKE_CURRENT_SOURCE_DIR}/../libs/logger ) + +# Link only external dependencies, not internal spectator libraries target_link_libraries(registry PUBLIC - spectator-config - spectator-meter-id - spectator-meter-types - spectator-writer-config - spectator-writer-wrapper - + spdlog::spdlog ) add_executable(registry-test test_registry.cpp) target_link_libraries(registry-test PRIVATE From c648c0b22d0d7df96e7fe245c01a416197a0b8d5 Mon Sep 17 00:00:00 2001 From: ecbadeaux Date: Fri, 27 Jun 2025 20:06:45 +0000 Subject: [PATCH 28/34] save work --- CMakeLists.txt | 2 +- libs/writer/writer_types/CMakeLists.txt | 1 + spectator/CMakeLists.txt | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 902405d..84204ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ option(BUILD_TESTS "Build the test suite" ON) # Find dependencies (handled by Conan) find_package(spdlog REQUIRED) find_package(GTest REQUIRED) -find_package(Boost REQUIRED COMPONENTS system) +find_package(Boost REQUIRED) # Build tests if enabled if(BUILD_TESTS) diff --git a/libs/writer/writer_types/CMakeLists.txt b/libs/writer/writer_types/CMakeLists.txt index 989d21b..35319f0 100644 --- a/libs/writer/writer_types/CMakeLists.txt +++ b/libs/writer/writer_types/CMakeLists.txt @@ -14,6 +14,7 @@ target_include_directories(spectator-writer-types target_link_libraries(spectator-writer-types PUBLIC spectator-logger + Boost::boost Boost::system ) diff --git a/spectator/CMakeLists.txt b/spectator/CMakeLists.txt index b3539be..cca311a 100644 --- a/spectator/CMakeLists.txt +++ b/spectator/CMakeLists.txt @@ -29,6 +29,8 @@ target_include_directories(registry target_link_libraries(registry PUBLIC spdlog::spdlog + Boost::boost + Boost::system ) add_executable(registry-test test_registry.cpp) target_link_libraries(registry-test PRIVATE From 6e255d794373d1c1d26e300c7fabb5a310c6545d Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Mon, 30 Jun 2025 01:38:45 -0500 Subject: [PATCH 29/34] fix header file naming --- libs/config/CMakeLists.txt | 2 +- libs/config/config.cpp | 8 ++++---- libs/config/config.h | 2 +- libs/config/test_config.cpp | 2 +- libs/logger/logger.h | 2 +- libs/meter/meter_id/CMakeLists.txt | 2 +- libs/meter/meter_id/meter_id.cpp | 4 ++-- libs/meter/meter_id/test_meter_id.cpp | 2 +- libs/meter/meter_types/CMakeLists.txt | 2 +- libs/meter/meter_types/include/age_gauge.h | 6 +++--- libs/meter/meter_types/include/counter.h | 6 +++--- libs/meter/meter_types/include/dist_summary.h | 6 +++--- libs/meter/meter_types/include/gauge.h | 6 +++--- libs/meter/meter_types/include/max_gauge.h | 6 +++--- libs/meter/meter_types/include/meter.h | 2 +- libs/meter/meter_types/include/monotonic_counter.h | 6 +++--- .../meter/meter_types/include/monotonic_counter_uint.h | 6 +++--- .../meter_types/include/percentile_dist_summary.h | 6 +++--- libs/meter/meter_types/include/percentile_timer.h | 6 +++--- libs/meter/meter_types/include/timer.h | 6 +++--- libs/meter/meter_types/test/test_age_gauge.cpp | 4 ++-- libs/meter/meter_types/test/test_counter.cpp | 4 ++-- libs/meter/meter_types/test/test_dist_summary.cpp | 4 ++-- libs/meter/meter_types/test/test_gauge.cpp | 4 ++-- libs/meter/meter_types/test/test_max_gauge.cpp | 4 ++-- libs/meter/meter_types/test/test_monotonic_counter.cpp | 4 ++-- .../meter_types/test/test_monotonic_counter_uint.cpp | 4 ++-- .../meter_types/test/test_percentile_dist_summary.cpp | 4 ++-- libs/meter/meter_types/test/test_percentile_timer.cpp | 4 ++-- libs/meter/meter_types/test/test_timer.cpp | 4 ++-- libs/utils/CMakeLists.txt | 2 +- libs/utils/include/util.h | 2 +- libs/utils/src/util.cpp | 2 +- libs/writer/writer_config/CMakeLists.txt | 2 +- libs/writer/writer_config/test_writer_config.cpp | 2 +- libs/writer/writer_config/writer_config.cpp | 4 ++-- libs/writer/writer_config/writer_config.h | 2 +- libs/writer/writer_types/CMakeLists.txt | 2 +- libs/writer/writer_types/include/memory_writer.h | 2 +- libs/writer/writer_types/include/udp_writer.h | 2 +- libs/writer/writer_types/include/uds_writer.h | 2 +- libs/writer/writer_types/src/memory_writer.cpp | 4 ++-- libs/writer/writer_types/src/udp_writer.cpp | 4 ++-- libs/writer/writer_types/src/uds_writer.cpp | 4 ++-- libs/writer/writer_types/test/test_memory_writer.cpp | 2 +- libs/writer/writer_types/test/test_udp_writer.cpp | 2 +- libs/writer/writer_types/test/test_uds_writer.cpp | 2 +- libs/writer/writer_wrapper/CMakeLists.txt | 7 +++++++ libs/writer/writer_wrapper/test_writer.cpp | 8 ++++---- libs/writer/writer_wrapper/writer.cpp | 6 +++--- libs/writer/writer_wrapper/writer.h | 4 ++-- libs/writer/writer_wrapper/writer_test_helper.h | 2 +- performance_tests/performance_test.cpp | 2 +- spectator/CMakeLists.txt | 2 +- spectator/registry.cpp | 2 +- spectator/registry.h | 10 +++++----- spectator/test_registry.cpp | 6 +++--- 57 files changed, 113 insertions(+), 106 deletions(-) diff --git a/libs/config/CMakeLists.txt b/libs/config/CMakeLists.txt index f324ef3..a3609ec 100644 --- a/libs/config/CMakeLists.txt +++ b/libs/config/CMakeLists.txt @@ -3,7 +3,7 @@ add_library(spectator-config ) target_include_directories(spectator-config - PUBLIC ${CMAKE_SOURCE_DIR} + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ) target_link_libraries(spectator-config diff --git a/libs/config/config.cpp b/libs/config/config.cpp index 3f16412..b37dc8d 100644 --- a/libs/config/config.cpp +++ b/libs/config/config.cpp @@ -1,8 +1,8 @@ -#include +#include -#include -#include -#include +#include +#include +#include #include #include diff --git a/libs/config/config.h b/libs/config/config.h index 0ecd7dd..82e1dc1 100644 --- a/libs/config/config.h +++ b/libs/config/config.h @@ -3,7 +3,7 @@ #include #include -#include +#include class Config { diff --git a/libs/config/test_config.cpp b/libs/config/test_config.cpp index 716adf1..3937d7c 100644 --- a/libs/config/test_config.cpp +++ b/libs/config/test_config.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include #include // Enhanced helper to temporarily modify an environment variable for testing diff --git a/libs/logger/logger.h b/libs/logger/logger.h index 5450ecc..d1600ac 100644 --- a/libs/logger/logger.h +++ b/libs/logger/logger.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/meter/meter_id/CMakeLists.txt b/libs/meter/meter_id/CMakeLists.txt index 52dcbc6..c296453 100644 --- a/libs/meter/meter_id/CMakeLists.txt +++ b/libs/meter/meter_id/CMakeLists.txt @@ -4,7 +4,7 @@ add_library(spectator-meter-id target_include_directories(spectator-meter-id PUBLIC - ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} ) target_link_libraries(spectator-meter-id diff --git a/libs/meter/meter_id/meter_id.cpp b/libs/meter/meter_id/meter_id.cpp index 179b2be..eafa999 100644 --- a/libs/meter/meter_id/meter_id.cpp +++ b/libs/meter/meter_id/meter_id.cpp @@ -1,6 +1,6 @@ -#include +#include -#include +#include #include #include diff --git a/libs/meter/meter_id/test_meter_id.cpp b/libs/meter/meter_id/test_meter_id.cpp index b024972..d2bd71d 100644 --- a/libs/meter/meter_id/test_meter_id.cpp +++ b/libs/meter/meter_id/test_meter_id.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/libs/meter/meter_types/CMakeLists.txt b/libs/meter/meter_types/CMakeLists.txt index 77dbc9f..86c6e00 100644 --- a/libs/meter/meter_types/CMakeLists.txt +++ b/libs/meter/meter_types/CMakeLists.txt @@ -2,7 +2,7 @@ add_library(spectator-meter-types INTERFACE) target_include_directories(spectator-meter-types INTERFACE - ${CMAKE_SOURCE_DIR} + include ) # List all the test files diff --git a/libs/meter/meter_types/include/age_gauge.h b/libs/meter/meter_types/include/age_gauge.h index 1ee7f54..6f52a90 100644 --- a/libs/meter/meter_types/include/age_gauge.h +++ b/libs/meter/meter_types/include/age_gauge.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include diff --git a/libs/meter/meter_types/include/counter.h b/libs/meter/meter_types/include/counter.h index 1df957f..5a0fc42 100644 --- a/libs/meter/meter_types/include/counter.h +++ b/libs/meter/meter_types/include/counter.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include diff --git a/libs/meter/meter_types/include/dist_summary.h b/libs/meter/meter_types/include/dist_summary.h index 00f56f7..4448d6e 100644 --- a/libs/meter/meter_types/include/dist_summary.h +++ b/libs/meter/meter_types/include/dist_summary.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include diff --git a/libs/meter/meter_types/include/gauge.h b/libs/meter/meter_types/include/gauge.h index efb839e..bcb6352 100644 --- a/libs/meter/meter_types/include/gauge.h +++ b/libs/meter/meter_types/include/gauge.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include #include diff --git a/libs/meter/meter_types/include/max_gauge.h b/libs/meter/meter_types/include/max_gauge.h index 8ee514b..6bc190d 100644 --- a/libs/meter/meter_types/include/max_gauge.h +++ b/libs/meter/meter_types/include/max_gauge.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include diff --git a/libs/meter/meter_types/include/meter.h b/libs/meter/meter_types/include/meter.h index 1f102b0..84286c0 100644 --- a/libs/meter/meter_types/include/meter.h +++ b/libs/meter/meter_types/include/meter.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include class Meter diff --git a/libs/meter/meter_types/include/monotonic_counter.h b/libs/meter/meter_types/include/monotonic_counter.h index 689bdf8..41f4889 100644 --- a/libs/meter/meter_types/include/monotonic_counter.h +++ b/libs/meter/meter_types/include/monotonic_counter.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include diff --git a/libs/meter/meter_types/include/monotonic_counter_uint.h b/libs/meter/meter_types/include/monotonic_counter_uint.h index db056a9..386dc8a 100644 --- a/libs/meter/meter_types/include/monotonic_counter_uint.h +++ b/libs/meter/meter_types/include/monotonic_counter_uint.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include diff --git a/libs/meter/meter_types/include/percentile_dist_summary.h b/libs/meter/meter_types/include/percentile_dist_summary.h index 5f53599..b269d22 100644 --- a/libs/meter/meter_types/include/percentile_dist_summary.h +++ b/libs/meter/meter_types/include/percentile_dist_summary.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include diff --git a/libs/meter/meter_types/include/percentile_timer.h b/libs/meter/meter_types/include/percentile_timer.h index 7a8ae77..4b41c22 100644 --- a/libs/meter/meter_types/include/percentile_timer.h +++ b/libs/meter/meter_types/include/percentile_timer.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include diff --git a/libs/meter/meter_types/include/timer.h b/libs/meter/meter_types/include/timer.h index f049182..6b44b30 100644 --- a/libs/meter/meter_types/include/timer.h +++ b/libs/meter/meter_types/include/timer.h @@ -1,8 +1,8 @@ #pragma once -#include -#include -#include +#include +#include +#include #include diff --git a/libs/meter/meter_types/test/test_age_gauge.cpp b/libs/meter/meter_types/test/test_age_gauge.cpp index c6cefb7..18e19be 100644 --- a/libs/meter/meter_types/test/test_age_gauge.cpp +++ b/libs/meter/meter_types/test/test_age_gauge.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include diff --git a/libs/meter/meter_types/test/test_counter.cpp b/libs/meter/meter_types/test/test_counter.cpp index 3a8e21e..70f0aa2 100644 --- a/libs/meter/meter_types/test/test_counter.cpp +++ b/libs/meter/meter_types/test/test_counter.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include diff --git a/libs/meter/meter_types/test/test_dist_summary.cpp b/libs/meter/meter_types/test/test_dist_summary.cpp index 7695515..04810bc 100644 --- a/libs/meter/meter_types/test/test_dist_summary.cpp +++ b/libs/meter/meter_types/test/test_dist_summary.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include diff --git a/libs/meter/meter_types/test/test_gauge.cpp b/libs/meter/meter_types/test/test_gauge.cpp index 8de2060..535af14 100644 --- a/libs/meter/meter_types/test/test_gauge.cpp +++ b/libs/meter/meter_types/test/test_gauge.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include diff --git a/libs/meter/meter_types/test/test_max_gauge.cpp b/libs/meter/meter_types/test/test_max_gauge.cpp index b941bed..0892629 100644 --- a/libs/meter/meter_types/test/test_max_gauge.cpp +++ b/libs/meter/meter_types/test/test_max_gauge.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include diff --git a/libs/meter/meter_types/test/test_monotonic_counter.cpp b/libs/meter/meter_types/test/test_monotonic_counter.cpp index dbef4af..33d862b 100644 --- a/libs/meter/meter_types/test/test_monotonic_counter.cpp +++ b/libs/meter/meter_types/test/test_monotonic_counter.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include diff --git a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp index c921f83..cadd8f1 100644 --- a/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp +++ b/libs/meter/meter_types/test/test_monotonic_counter_uint.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include diff --git a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp index 907d456..80c1d75 100644 --- a/libs/meter/meter_types/test/test_percentile_dist_summary.cpp +++ b/libs/meter/meter_types/test/test_percentile_dist_summary.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include diff --git a/libs/meter/meter_types/test/test_percentile_timer.cpp b/libs/meter/meter_types/test/test_percentile_timer.cpp index 8f6731e..182ca00 100644 --- a/libs/meter/meter_types/test/test_percentile_timer.cpp +++ b/libs/meter/meter_types/test/test_percentile_timer.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include diff --git a/libs/meter/meter_types/test/test_timer.cpp b/libs/meter/meter_types/test/test_timer.cpp index 3675c15..2275759 100644 --- a/libs/meter/meter_types/test/test_timer.cpp +++ b/libs/meter/meter_types/test/test_timer.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include #include diff --git a/libs/utils/CMakeLists.txt b/libs/utils/CMakeLists.txt index 1d7e6af..5b1edb5 100644 --- a/libs/utils/CMakeLists.txt +++ b/libs/utils/CMakeLists.txt @@ -6,7 +6,7 @@ add_library(spectator-utils STATIC target_include_directories(spectator-utils PUBLIC - ${CMAKE_SOURCE_DIR} + include ) target_link_libraries(spectator-utils diff --git a/libs/utils/include/util.h b/libs/utils/include/util.h index b320327..694ac85 100644 --- a/libs/utils/include/util.h +++ b/libs/utils/include/util.h @@ -6,7 +6,7 @@ #include #include -#include +#include struct ProtocolLine { diff --git a/libs/utils/src/util.cpp b/libs/utils/src/util.cpp index 6e482f1..77ee350 100644 --- a/libs/utils/src/util.cpp +++ b/libs/utils/src/util.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/libs/writer/writer_config/CMakeLists.txt b/libs/writer/writer_config/CMakeLists.txt index 20c2f6a..69fc91e 100644 --- a/libs/writer/writer_config/CMakeLists.txt +++ b/libs/writer/writer_config/CMakeLists.txt @@ -5,7 +5,7 @@ add_library(spectator-writer-config STATIC target_include_directories(spectator-writer-config PUBLIC - ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} ) diff --git a/libs/writer/writer_config/test_writer_config.cpp b/libs/writer/writer_config/test_writer_config.cpp index 228fb75..a547764 100644 --- a/libs/writer/writer_config/test_writer_config.cpp +++ b/libs/writer/writer_config/test_writer_config.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include diff --git a/libs/writer/writer_config/writer_config.cpp b/libs/writer/writer_config/writer_config.cpp index d1936a0..70020c0 100644 --- a/libs/writer/writer_config/writer_config.cpp +++ b/libs/writer/writer_config/writer_config.cpp @@ -1,6 +1,6 @@ -#include +#include -#include +#include struct WriterConfigConstants { diff --git a/libs/writer/writer_config/writer_config.h b/libs/writer/writer_config/writer_config.h index 0da7610..4f35a2b 100644 --- a/libs/writer/writer_config/writer_config.h +++ b/libs/writer/writer_config/writer_config.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/writer/writer_types/CMakeLists.txt b/libs/writer/writer_types/CMakeLists.txt index 35319f0..058b58b 100644 --- a/libs/writer/writer_types/CMakeLists.txt +++ b/libs/writer/writer_types/CMakeLists.txt @@ -8,7 +8,7 @@ add_library(spectator-writer-types target_include_directories(spectator-writer-types PUBLIC - ${CMAKE_SOURCE_DIR} + include ) target_link_libraries(spectator-writer-types diff --git a/libs/writer/writer_types/include/memory_writer.h b/libs/writer/writer_types/include/memory_writer.h index 32d38fe..892fadc 100644 --- a/libs/writer/writer_types/include/memory_writer.h +++ b/libs/writer/writer_types/include/memory_writer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/writer/writer_types/include/udp_writer.h b/libs/writer/writer_types/include/udp_writer.h index 72d9119..3737482 100644 --- a/libs/writer/writer_types/include/udp_writer.h +++ b/libs/writer/writer_types/include/udp_writer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/writer/writer_types/include/uds_writer.h b/libs/writer/writer_types/include/uds_writer.h index 22adac3..16c6ea9 100644 --- a/libs/writer/writer_types/include/uds_writer.h +++ b/libs/writer/writer_types/include/uds_writer.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/libs/writer/writer_types/src/memory_writer.cpp b/libs/writer/writer_types/src/memory_writer.cpp index 07e1f7c..bfa330e 100644 --- a/libs/writer/writer_types/src/memory_writer.cpp +++ b/libs/writer/writer_types/src/memory_writer.cpp @@ -1,6 +1,6 @@ -#include +#include -#include +#include void MemoryWriter::Write(const std::string& message) { diff --git a/libs/writer/writer_types/src/udp_writer.cpp b/libs/writer/writer_types/src/udp_writer.cpp index 5d1cdf0..638bc87 100644 --- a/libs/writer/writer_types/src/udp_writer.cpp +++ b/libs/writer/writer_types/src/udp_writer.cpp @@ -1,6 +1,6 @@ -#include +#include -#include +#include UDPWriter::UDPWriter(const std::string& host, int port) : m_host(host), m_port(port) { diff --git a/libs/writer/writer_types/src/uds_writer.cpp b/libs/writer/writer_types/src/uds_writer.cpp index 4dea66c..5533fba 100644 --- a/libs/writer/writer_types/src/uds_writer.cpp +++ b/libs/writer/writer_types/src/uds_writer.cpp @@ -1,6 +1,6 @@ -#include +#include -#include +#include #include diff --git a/libs/writer/writer_types/test/test_memory_writer.cpp b/libs/writer/writer_types/test/test_memory_writer.cpp index d35b76b..011a782 100644 --- a/libs/writer/writer_types/test/test_memory_writer.cpp +++ b/libs/writer/writer_types/test/test_memory_writer.cpp @@ -1,4 +1,4 @@ -#include +#include #include TEST(MemoryWriterTest, IsEmpty) diff --git a/libs/writer/writer_types/test/test_udp_writer.cpp b/libs/writer/writer_types/test/test_udp_writer.cpp index 5261dd6..4d0ef91 100644 --- a/libs/writer/writer_types/test/test_udp_writer.cpp +++ b/libs/writer/writer_types/test/test_udp_writer.cpp @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/libs/writer/writer_types/test/test_uds_writer.cpp b/libs/writer/writer_types/test/test_uds_writer.cpp index 0274edf..e8588f3 100644 --- a/libs/writer/writer_types/test/test_uds_writer.cpp +++ b/libs/writer/writer_types/test/test_uds_writer.cpp @@ -1,5 +1,5 @@ -#include +#include #include #include "../test_utils/uds_server/uds_server.h" diff --git a/libs/writer/writer_wrapper/CMakeLists.txt b/libs/writer/writer_wrapper/CMakeLists.txt index 54fa682..4f68a4c 100644 --- a/libs/writer/writer_wrapper/CMakeLists.txt +++ b/libs/writer/writer_wrapper/CMakeLists.txt @@ -2,6 +2,11 @@ add_library(spectator-writer-wrapper writer.cpp ) +target_include_directories(spectator-writer-wrapper + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + target_link_libraries(spectator-writer-wrapper PUBLIC spectator-logger @@ -17,6 +22,8 @@ target_link_libraries(writer_test GTest::GTest GTest::Main spectator-writer-wrapper + spectator-meter-types + spectator-meter-id uds_server_lib ) add_test(NAME writer_test COMMAND writer_test) \ No newline at end of file diff --git a/libs/writer/writer_wrapper/test_writer.cpp b/libs/writer/writer_wrapper/test_writer.cpp index c98a418..5147764 100644 --- a/libs/writer/writer_wrapper/test_writer.cpp +++ b/libs/writer/writer_wrapper/test_writer.cpp @@ -1,7 +1,7 @@ -#include -#include -#include -#include +#include +#include +#include +#include #include #include diff --git a/libs/writer/writer_wrapper/writer.cpp b/libs/writer/writer_wrapper/writer.cpp index 020b38c..95cdf13 100644 --- a/libs/writer/writer_wrapper/writer.cpp +++ b/libs/writer/writer_wrapper/writer.cpp @@ -1,7 +1,7 @@ -#include +#include -#include -#include +#include +#include #include static constexpr auto NEW_LINE = '\n'; diff --git a/libs/writer/writer_wrapper/writer.h b/libs/writer/writer_wrapper/writer.h index b6b9eec..01350ee 100644 --- a/libs/writer/writer_wrapper/writer.h +++ b/libs/writer/writer_wrapper/writer.h @@ -1,7 +1,7 @@ #pragma once -#include -#include +#include +#include #include #include diff --git a/libs/writer/writer_wrapper/writer_test_helper.h b/libs/writer/writer_wrapper/writer_test_helper.h index 0b1b08c..0803fee 100644 --- a/libs/writer/writer_wrapper/writer_test_helper.h +++ b/libs/writer/writer_wrapper/writer_test_helper.h @@ -1,6 +1,6 @@ #pragma once -#include +#include /** * WriterTestHelper - A utility class to help with testing Writer functionality diff --git a/performance_tests/performance_test.cpp b/performance_tests/performance_test.cpp index 40351aa..87b6c8f 100644 --- a/performance_tests/performance_test.cpp +++ b/performance_tests/performance_test.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include diff --git a/spectator/CMakeLists.txt b/spectator/CMakeLists.txt index cca311a..0bb3966 100644 --- a/spectator/CMakeLists.txt +++ b/spectator/CMakeLists.txt @@ -14,7 +14,7 @@ add_library(registry target_include_directories(registry PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../libs/config ${CMAKE_CURRENT_SOURCE_DIR}/../libs/meter/meter_id ${CMAKE_CURRENT_SOURCE_DIR}/../libs/meter/meter_types/include diff --git a/spectator/registry.cpp b/spectator/registry.cpp index a1f171e..d86e910 100644 --- a/spectator/registry.cpp +++ b/spectator/registry.cpp @@ -1,4 +1,4 @@ -#include +#include std::pair ParseUdpAddress(const std::string& address) diff --git a/spectator/registry.h b/spectator/registry.h index 148a52f..d8971b6 100644 --- a/spectator/registry.h +++ b/spectator/registry.h @@ -1,10 +1,10 @@ #pragma once -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/spectator/test_registry.cpp b/spectator/test_registry.cpp index 7011184..657df44 100644 --- a/spectator/test_registry.cpp +++ b/spectator/test_registry.cpp @@ -1,10 +1,10 @@ #include #include -#include -#include +#include +#include -#include +#include TEST(RegistryTest, Close) { From 052e52c0f7fbec6f7643cadfc88948be3ac9e3a6 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Thu, 3 Jul 2025 21:01:17 +0000 Subject: [PATCH 30/34] last fixes --- CMakeLists.txt | 10 ++---- README.md | 12 ++----- conanfile.py | 1 - libs/config/CMakeLists.txt | 2 +- libs/config/config.cpp | 18 +++++----- libs/config/config.h | 4 +-- libs/logger/logger.h | 29 ++++++--------- .../writer_config/test_writer_config.cpp | 1 - libs/writer/writer_config/writer_config.cpp | 2 -- libs/writer/writer_config/writer_config.h | 2 -- .../writer/writer_types/src/memory_writer.cpp | 3 -- libs/writer/writer_types/src/udp_writer.cpp | 4 +-- libs/writer/writer_types/src/uds_writer.cpp | 11 +++--- libs/writer/writer_wrapper/writer.cpp | 36 +++++-------------- setup-venv.sh | 0 spectator/registry.cpp | 12 ++----- spectator/registry.h | 2 +- 17 files changed, 48 insertions(+), 101 deletions(-) mode change 100644 => 100755 setup-venv.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 84204ef..039e65e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,23 +1,19 @@ cmake_minimum_required(VERSION 3.15) -project(spectator-cpp VERSION 2.0 LANGUAGES CXX) +project(spectator-cpp LANGUAGES CXX) # Set C++ standard set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -# Options -option(BUILD_TESTS "Build the test suite" ON) +add_compile_options(-pedantic -Werror -Wall -Wno-missing-braces -fno-omit-frame-pointer) # Find dependencies (handled by Conan) find_package(spdlog REQUIRED) find_package(GTest REQUIRED) find_package(Boost REQUIRED) -# Build tests if enabled -if(BUILD_TESTS) - enable_testing() -endif() +include(CTest) # Add subdirectories add_subdirectory(libs) diff --git a/README.md b/README.md index d80fe38..7e67e19 100644 --- a/README.md +++ b/README.md @@ -2,21 +2,15 @@ # Spectator-cpp -This implements a basic [Spectator](https://github.com/Netflix/spectator) library for instrumenting Go applications. It +This implements a basic [Spectator](https://github.com/Netflix/spectator) library for instrumenting CPP applications. It consists of a thin client designed to send metrics through [spectatord](https://github.com/Netflix-Skunkworks/spectatord). -## Instrumenting Code - -```C++ - -``` - ## High-Volume Publishing By default, the library sends every meter change to the spectatord sidecar immediately. This involves a blocking `send` call and underlying system calls, and may not be the most efficient way to publish metrics in high-volume -use cases. For this purpose a simple buffering functionality in `Publisher` is implemented, and it can be turned -on by passing a buffer size to the `spectator::Config` constructor. It is important to note that, until this buffer +use cases. For this purpose a simple buffering functionality is implemented, and it can be turned +on by passing a buffer size to the `WriterConfig` constructor. It is important to note that, until this buffer fills up, the `Publisher` will not send any meters to the sidecar. Therefore, if your application doesn't emit meters at a high rate, you should either keep the buffer very small, or do not configure a buffer size at all, which will fall back to the "publish immediately" mode of operation. diff --git a/conanfile.py b/conanfile.py index ada0578..a6604bd 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,6 +1,5 @@ from conan import ConanFile - class SpectatorCppConan(ConanFile): settings = "os", "compiler", "build_type", "arch" requires = ( diff --git a/libs/config/CMakeLists.txt b/libs/config/CMakeLists.txt index a3609ec..f53c763 100644 --- a/libs/config/CMakeLists.txt +++ b/libs/config/CMakeLists.txt @@ -19,9 +19,9 @@ add_executable(config-tests target_link_libraries(config-tests PRIVATE spectator-config + spectator-writer-config GTest::gtest GTest::gtest_main - spectator-writer-config ) add_test( diff --git a/libs/config/config.cpp b/libs/config/config.cpp index b37dc8d..b513157 100644 --- a/libs/config/config.cpp +++ b/libs/config/config.cpp @@ -9,10 +9,10 @@ struct ConfigConstants { - static constexpr auto container = "nf.container"; - static constexpr auto process = "nf.process"; - static constexpr auto envVarContainer = "TITUS_CONTAINER_NAME"; - static constexpr auto envVarProcess = "TITUS_PROCESS_NAME"; + static constexpr auto Container = "nf.container"; + static constexpr auto Process = "nf.process"; + static constexpr auto EnvVarContainer = "TITUS_CONTAINER_NAME"; + static constexpr auto EnvVarProcess = "TITUS_PROCESS_NAME"; }; std::unordered_map CalculateTags( @@ -20,15 +20,15 @@ std::unordered_map CalculateTags( { std::unordered_map valid_tags; - const char* container_name = std::getenv(ConfigConstants::envVarContainer); - const char* process_name = std::getenv(ConfigConstants::envVarProcess); - + const char* container_name = std::getenv(ConfigConstants::EnvVarContainer); + const char* process_name = std::getenv(ConfigConstants::EnvVarProcess); + if (container_name != nullptr) { std::string container_str(container_name); if (IsEmptyOrWhitespace(container_str) == false) { - valid_tags[ConfigConstants::container] = container_str; + valid_tags[ConfigConstants::Container] = container_str; } } @@ -37,7 +37,7 @@ std::unordered_map CalculateTags( std::string process_str(process_name); if (IsEmptyOrWhitespace(process_str) == false) { - valid_tags[ConfigConstants::process] = process_str; + valid_tags[ConfigConstants::Process] = process_str; } } diff --git a/libs/config/config.h b/libs/config/config.h index 82e1dc1..7a20c6b 100644 --- a/libs/config/config.h +++ b/libs/config/config.h @@ -13,8 +13,8 @@ class Config ~Config() = default; Config(const Config& other) = default; Config& operator=(const Config& other) = delete; - Config(Config&& other) noexcept = delete; - Config& operator=(Config&& other) noexcept = delete; + Config(Config&& other) = delete; + Config& operator=(Config&& other) = delete; const std::unordered_map& GetExtraTags() const noexcept { return m_extraTags; } diff --git a/libs/logger/logger.h b/libs/logger/logger.h index d1600ac..503193d 100644 --- a/libs/logger/logger.h +++ b/libs/logger/logger.h @@ -16,8 +16,7 @@ constexpr const char* kMainLogger = "spectator"; class Logger final : public Singleton { private: - spdlog::logger* m_logger; // Use raw pointer, not unique_ptr - inline static bool s_loggingEnabled = true; // Static flag to control logging (C++17 inline initialization) + std::shared_ptr m_logger; friend class Singleton; @@ -25,13 +24,7 @@ class Logger final : public Singleton { try { - spdlog::init_thread_pool(8192, 1); - auto sink = std::make_shared(); - auto shared_logger = std::make_shared(kMainLogger, sink, spdlog::thread_pool(), - spdlog::async_overflow_policy::block); - shared_logger->set_level(spdlog::level::debug); - spdlog::register_logger(shared_logger); - m_logger = shared_logger.get(); + m_logger = spdlog::create_async_nb(kMainLogger); } catch (const spdlog::spdlog_ex& ex) { @@ -47,49 +40,49 @@ class Logger final : public Singleton Logger& operator=(Logger&&) = delete; public: - static spdlog::logger* GetLogger() { return GetInstance().m_logger; } + static spdlog::logger* GetLogger() { return GetInstance().m_logger.get(); } static void debug(const std::string& msg) { - if (s_loggingEnabled) GetLogger()->debug(msg); + GetLogger()->debug(msg); } static void info(const std::string& msg) { - if (s_loggingEnabled) GetLogger()->info(msg); + GetLogger()->info(msg); } static void warn(const std::string& msg) { - if (s_loggingEnabled) GetLogger()->warn(msg); + GetLogger()->warn(msg); } static void error(const std::string& msg) { - if (s_loggingEnabled) GetLogger()->error(msg); + GetLogger()->error(msg); } template static void debug(fmt::format_string fmt, Args&&... args) { - if (s_loggingEnabled) GetLogger()->debug(fmt, std::forward(args)...); + GetLogger()->debug(fmt, std::forward(args)...); } template static void info(fmt::format_string fmt, Args&&... args) { - if (s_loggingEnabled) GetLogger()->info(fmt, std::forward(args)...); + GetLogger()->info(fmt, std::forward(args)...); } template static void warn(fmt::format_string fmt, Args&&... args) { - if (s_loggingEnabled) GetLogger()->warn(fmt, std::forward(args)...); + GetLogger()->warn(fmt, std::forward(args)...); } template static void error(fmt::format_string fmt, Args&&... args) { - if (s_loggingEnabled) GetLogger()->error(fmt, std::forward(args)...); + GetLogger()->error(fmt, std::forward(args)...); } }; diff --git a/libs/writer/writer_config/test_writer_config.cpp b/libs/writer/writer_config/test_writer_config.cpp index a547764..3f3595d 100644 --- a/libs/writer/writer_config/test_writer_config.cpp +++ b/libs/writer/writer_config/test_writer_config.cpp @@ -96,7 +96,6 @@ TEST_F(WriterConfigTest, BufferingConstructor) const WriterConfig config(WriterTypes::UDP, 2048); EXPECT_EQ(config.GetType(), WriterType::UDP); EXPECT_EQ(config.GetBufferSize(), 2048); - EXPECT_TRUE(config.IsBufferingEnabled()); } TEST_F(WriterConfigTest, InvalidWriterType) diff --git a/libs/writer/writer_config/writer_config.cpp b/libs/writer/writer_config/writer_config.cpp index 70020c0..8a108af 100644 --- a/libs/writer/writer_config/writer_config.cpp +++ b/libs/writer/writer_config/writer_config.cpp @@ -51,7 +51,5 @@ WriterConfig::WriterConfig(const std::string& type, const unsigned int bufferSiz : WriterConfig(type) // Constructor delegation { m_bufferSize = bufferSize; - m_isBufferingEnabled = true; Logger::info("WriterConfig buffering enabled with size: {}", m_bufferSize); - } \ No newline at end of file diff --git a/libs/writer/writer_config/writer_config.h b/libs/writer/writer_config/writer_config.h index 4f35a2b..d007a53 100644 --- a/libs/writer/writer_config/writer_config.h +++ b/libs/writer/writer_config/writer_config.h @@ -13,12 +13,10 @@ class WriterConfig [[nodiscard]] const WriterType& GetType() const noexcept { return m_type; } [[nodiscard]] unsigned int GetBufferSize() const noexcept { return m_bufferSize; } - [[nodiscard]] bool IsBufferingEnabled() const noexcept { return m_isBufferingEnabled; } [[nodiscard]] const std::string& GetLocation() const noexcept { return m_location; } private: WriterType m_type; std::string m_location; unsigned int m_bufferSize = 0; - bool m_isBufferingEnabled = false; }; \ No newline at end of file diff --git a/libs/writer/writer_types/src/memory_writer.cpp b/libs/writer/writer_types/src/memory_writer.cpp index bfa330e..b75ad02 100644 --- a/libs/writer/writer_types/src/memory_writer.cpp +++ b/libs/writer/writer_types/src/memory_writer.cpp @@ -5,19 +5,16 @@ void MemoryWriter::Write(const std::string& message) { this->m_messages.push_back(message); - Logger::debug("MemoryWriter::Writing: {}", message); } void MemoryWriter::Close() { this->Clear(); - Logger::debug("MemoryWriter::Closed"); } void MemoryWriter::Clear() { this->m_messages.clear(); - Logger::debug("MemoryWriter::Cleared messages"); } const std::string& MemoryWriter::LastLine() const noexcept diff --git a/libs/writer/writer_types/src/udp_writer.cpp b/libs/writer/writer_types/src/udp_writer.cpp index 638bc87..967b76d 100644 --- a/libs/writer/writer_types/src/udp_writer.cpp +++ b/libs/writer/writer_types/src/udp_writer.cpp @@ -43,7 +43,7 @@ void UDPWriter::Write(const std::string& message) try } else if (sent != message.size()) { - Logger::warn("UDPWriter: Sent only {} bytes out of {} bytes", sent, message.size()); + Logger::error("UDPWriter: Sent only {} bytes out of {} bytes", sent, message.size()); } } catch (const std::exception& e) @@ -59,7 +59,7 @@ void UDPWriter::Close() try m_socket->close(ec); if (ec) { - Logger::warn("UDPWriter: Error when closing socket: {}", ec.message()); + Logger::error("UDPWriter: Error when closing socket: {}", ec.message()); } } diff --git a/libs/writer/writer_types/src/uds_writer.cpp b/libs/writer/writer_types/src/uds_writer.cpp index 5533fba..17942f9 100644 --- a/libs/writer/writer_types/src/uds_writer.cpp +++ b/libs/writer/writer_types/src/uds_writer.cpp @@ -46,7 +46,6 @@ bool UDSWriter::connect() } m_isOpen = true; - Logger::debug("UDS Writer: Connected to {}", m_socketPath); return true; } catch (const std::exception& e) @@ -75,9 +74,9 @@ void UDSWriter::Write(const std::string& message) Logger::error("UDS Writer: Failed to send message - {}", ec.message()); m_isOpen = false; // Mark as disconnected on error } - else + if (sent < message.size()) { - Logger::debug("UDS Writer: Sent message ({} bytes)", sent); + Logger::error("UDS Writer: Sent only {} bytes out of {} bytes", sent, message.size()); } } catch (const std::exception& e) @@ -98,15 +97,13 @@ void UDSWriter::Close() if (ec) { - Logger::warn("UDS Writer: Error closing socket - {}", ec.message()); + Logger::error("UDS Writer: Error closing socket - {}", ec.message()); } } catch (const std::exception& e) { - Logger::warn("UDS Writer: Exception while closing socket - {}", e.what()); + Logger::error("UDS Writer: Exception while closing socket - {}", e.what()); } } - m_isOpen = false; - Logger::debug("UDS Writer: Connection closed"); } diff --git a/libs/writer/writer_wrapper/writer.cpp b/libs/writer/writer_wrapper/writer.cpp index 95cdf13..fe98eb0 100644 --- a/libs/writer/writer_wrapper/writer.cpp +++ b/libs/writer/writer_wrapper/writer.cpp @@ -33,15 +33,15 @@ void Writer::Initialize(WriterType type, const std::string& param, int port, uns { case WriterType::Memory: instance.m_impl = std::make_unique(); - Logger::info("Writer initialized as MemoryWriter"); + Logger::info("WriterWrapper initialized as MemoryWriter"); break; case WriterType::UDP: instance.m_impl = std::make_unique(param, port); - Logger::info("Writer initialized as UDPWriter with host: {} and port: {}", param, port); + Logger::info("WriterWrapper initialized as UDPWriter with host: {} and port: {}", param, port); break; case WriterType::Unix: instance.m_impl = std::make_unique(param); - Logger::info("Writer initialized as UnixWriter with socket path: {}", param); + Logger::info("WriterWrapper initialized as UnixWriter with socket path: {}", param); break; default: throw std::runtime_error("Unsupported writer type"); @@ -83,12 +83,11 @@ void Writer::Reset() } catch (const std::exception& e) { - Logger::warn("Exception while closing writer during reset: {}", e.what()); + Logger::error("Exception while closing writer during reset: {}", e.what()); } } instance.m_impl.reset(); - Logger::info("Writer has been reset"); } @@ -102,15 +101,7 @@ void Writer::TryToSend(const std::string& message) return; } - try - { - instance.m_impl->Write(message); - Logger::debug("Message sent successfully: {}", message); - } - catch (const std::exception& e) - { - Logger::error("Failed to send message: {}", e.what()); - } + instance.m_impl->Write(message); } void Writer::ThreadSend() @@ -153,7 +144,7 @@ void Writer::BufferedWrite(const std::string& message) lock, [&instance] { return instance.buffer.size() < instance.bufferSize || instance.shutdown.load(); }); if (instance.shutdown.load()) { - Logger::warn("Write operation aborted due to shutdown signal"); + Logger::info("Write operation aborted due to shutdown signal"); return; } instance.buffer.append(message); @@ -179,16 +170,8 @@ void Writer::Write(const std::string& message) return; } - try - { - // Call the member function using the pointer-to-member syntax - (instance.*instance.writeImpl)(message); - Logger::debug("Message written successfully: {}", message); - } - catch (const std::exception& e) - { - Logger::error("Failed to write message: {}", e.what()); - } + // Call the member function using the pointer-to-member syntax + (instance.*instance.writeImpl)(message); } void Writer::Close() @@ -197,14 +180,13 @@ void Writer::Close() if (!instance.m_impl) { - Logger::debug("Close called on uninitialized writer"); + Logger::error("Close called on uninitialized writer"); return; } try { instance.m_impl->Close(); - Logger::debug("Writer closed successfully"); } catch (const std::exception& e) { diff --git a/setup-venv.sh b/setup-venv.sh old mode 100644 new mode 100755 diff --git a/spectator/registry.cpp b/spectator/registry.cpp index d86e910..a33e7b1 100644 --- a/spectator/registry.cpp +++ b/spectator/registry.cpp @@ -13,11 +13,11 @@ std::pair ParseUdpAddress(const std::string& address) std::string ip = matches[1].str(); int port = std::stoi(matches[2]); - - // Optional: Validate port range if (port < 0 || port > 65535) + { throw std::runtime_error("Port number out of valid range (0-65535)"); - + } + return {ip, port}; } @@ -55,12 +55,6 @@ Registry::Registry(const Config& config) : m_config(config) } } -Registry::~Registry() -{ - // No need to close Writer here as it's a singleton - // and will live beyond Registry instances -} - MeterId Registry::new_id(const std::string& name, const std::unordered_map& tags) const { MeterId new_meter_id(name, tags); diff --git a/spectator/registry.h b/spectator/registry.h index d8971b6..8054b77 100644 --- a/spectator/registry.h +++ b/spectator/registry.h @@ -17,7 +17,7 @@ class Registry { public: explicit Registry(const Config& config); - ~Registry(); + ~Registry() = default; MeterId new_id(const std::string& name, const std::unordered_map& tags = {}) const; From f322f86ed87008435a831e5cfac851a6d4b67c0e Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Thu, 3 Jul 2025 21:24:04 +0000 Subject: [PATCH 31/34] fix log --- spectator/registry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spectator/registry.cpp b/spectator/registry.cpp index a33e7b1..5f6f676 100644 --- a/spectator/registry.cpp +++ b/spectator/registry.cpp @@ -50,7 +50,7 @@ Registry::Registry(const Config& config) : m_config(config) else if (config.GetWriterType() == WriterType::Unix) { auto socketPath = ParseUnixAddress(this->m_config.GetWriterLocation()); - Logger::info("Registry initializing UDS Writer at {null}:{null}"); + Logger::info("Registry initializing UDS Writer at {}", socketPath); Writer::Initialize(config.GetWriterType(), socketPath, 0, this->m_config.GetWriterBufferSize()); } } From a76292a756ac53ca15b425472a7fae4f43ed6d75 Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Thu, 3 Jul 2025 21:58:44 +0000 Subject: [PATCH 32/34] update writer wrapper --- libs/writer/writer_wrapper/writer.cpp | 35 +------------------ libs/writer/writer_wrapper/writer.h | 3 -- .../writer_wrapper/writer_test_helper.h | 3 -- 3 files changed, 1 insertion(+), 40 deletions(-) diff --git a/libs/writer/writer_wrapper/writer.cpp b/libs/writer/writer_wrapper/writer.cpp index fe98eb0..8cbeb86 100644 --- a/libs/writer/writer_wrapper/writer.cpp +++ b/libs/writer/writer_wrapper/writer.cpp @@ -19,6 +19,7 @@ Writer::~Writer() instance.sendingThread.join(); } } + this->Close(); } void Writer::Initialize(WriterType type, const std::string& param, int port, unsigned int bufferSize) @@ -71,36 +72,9 @@ void Writer::Initialize(WriterType type, const std::string& param, int port, uns } } -void Writer::Reset() -{ - auto& instance = GetInstance(); - - if (instance.m_impl) - { - try - { - instance.m_impl->Close(); - } - catch (const std::exception& e) - { - Logger::error("Exception while closing writer during reset: {}", e.what()); - } - } - - instance.m_impl.reset(); -} - - void Writer::TryToSend(const std::string& message) { const auto& instance = GetInstance(); - - if (!instance.m_impl) - { - Logger::error("Attempted to send with uninitialized writer implementation"); - return; - } - instance.m_impl->Write(message); } @@ -130,13 +104,6 @@ void Writer::ThreadSend() void Writer::BufferedWrite(const std::string& message) { auto& instance = GetInstance(); - - if (!instance.m_impl) - { - Logger::error("Attempted to write with uninitialized writer implementation"); - return; - } - { std::unique_lock lock(instance.writeMutex); // TODO: Optimize memory alloc to not exceed allocated size diff --git a/libs/writer/writer_wrapper/writer.h b/libs/writer/writer_wrapper/writer.h index 01350ee..6502d32 100644 --- a/libs/writer/writer_wrapper/writer.h +++ b/libs/writer/writer_wrapper/writer.h @@ -47,9 +47,6 @@ class Writer final : public Singleton static BaseWriter* GetImpl() { return Writer::GetInstance().m_impl.get(); } static WriterType GetWriterType() { return GetInstance().m_currentType; } - - static void Reset(); - std::unique_ptr m_impl; WriterType m_currentType = WriterType::Memory; // Default type bool bufferingEnabled = false; diff --git a/libs/writer/writer_wrapper/writer_test_helper.h b/libs/writer/writer_wrapper/writer_test_helper.h index 0803fee..881e40f 100644 --- a/libs/writer/writer_wrapper/writer_test_helper.h +++ b/libs/writer/writer_wrapper/writer_test_helper.h @@ -17,9 +17,6 @@ class WriterTestHelper Writer::Initialize(type, param, port, bufferSize); } - // Reset the Writer for testing purposes - static void ResetWriter() { Writer::Reset(); } - // Get the Writer's implementation for testing purposes static BaseWriter* GetImpl() { return Writer::GetInstance().m_impl.get(); } }; From d396b85ebc6060b9defe7378e71ee2ac999cacbf Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Mon, 7 Jul 2025 18:25:53 +0000 Subject: [PATCH 33/34] add workflow --- .github/workflows/build.yml | 43 +++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..d021c2c --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,43 @@ +name: Build + +on: + pull_request: + push: + branches: + - main + +jobs: + build: + if: ${{ github.repository == 'Netflix/spectator-cpp' }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Restore Conan Cache + id: conan-cache-restore + uses: actions/cache/restore@v4 + with: + path: | + /home/runner/.conan2 + /home/runner/work/spectator-cpp/spectator-cpp/cmake-build + key: ${{ runner.os }}-conan + + - name: Install System Dependencies + run: | + sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + sudo apt-get update && sudo apt-get install -y binutils-dev g++-13 libiberty-dev + + - name: Build + run: | + ./setup-venv.sh + source venv/bin/activate + ./build.sh + + - name: Save Conan Cache + id: conan-cache-save + uses: actions/cache/save@v4 + with: + path: | + /home/runner/.conan2 + /home/runner/work/spectator-cpp/spectator-cpp/cmake-build + key: ${{ steps.conan-cache-restore.outputs.cache-primary-key }} \ No newline at end of file From d5786eb859861dcb5854543c422915bec719ca1e Mon Sep 17 00:00:00 2001 From: Everett Badeaux Date: Mon, 7 Jul 2025 20:42:37 +0000 Subject: [PATCH 34/34] update build script --- build.sh | 16 +++++++--------- setup-venv.sh | 6 +++--- spectator/test_registry.cpp | 35 +++++++++++++++++------------------ 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/build.sh b/build.sh index 03ce752..d8564f5 100755 --- a/build.sh +++ b/build.sh @@ -19,7 +19,6 @@ NC="\033[0m" if [[ "$1" == "clean" ]]; then echo -e "${BLUE}==== clean ====${NC}" rm -rf "$BUILD_DIR" - rm -rf lib/spectator if [[ "$2" == "--confirm" ]]; then # remove all packages from the conan cache, to allow swapping between Release/Debug builds conan remove "*" --confirm @@ -34,6 +33,12 @@ if [[ "$OSTYPE" == "linux-gnu"* ]]; then fi fi +echo -e "${BLUE}==== env configuration ====${NC}" +echo "BUILD_DIR=$BUILD_DIR" +echo "BUILD_TYPE=$BUILD_TYPE" +echo "CC=$CC" +echo "CXX=$CXX" + if [[ ! -f "$HOME/.conan2/profiles/default" ]]; then echo -e "${BLUE}==== create default profile ====${NC}" conan profile detect @@ -41,14 +46,7 @@ fi if [[ ! -d $BUILD_DIR ]]; then echo -e "${BLUE}==== install required dependencies ====${NC}" - if [[ "$BUILD_TYPE" == "Debug" ]]; then - conan install . --output-folder="$BUILD_DIR" --build="*" --settings=build_type="$BUILD_TYPE" - else - conan install . --output-folder="$BUILD_DIR" --build=missing - fi - - echo -e "${BLUE}==== install source dependencies ====${NC}" - conan source . + conan install . --output-folder="$BUILD_DIR" --build="*" --settings=build_type="$BUILD_TYPE" fi pushd "$BUILD_DIR" diff --git a/setup-venv.sh b/setup-venv.sh index 94532d8..422d0b7 100755 --- a/setup-venv.sh +++ b/setup-venv.sh @@ -15,7 +15,7 @@ $PYTHON3 -m venv venv source venv/bin/activate if [[ -f requirements.txt ]]; then - # use the virtualenv python - python -m pip install --upgrade pip wheel - python -m pip install --requirement requirements.txt + # use the virtualenv python + python -m pip install --upgrade pip wheel + python -m pip install --requirement requirements.txt fi \ No newline at end of file diff --git a/spectator/test_registry.cpp b/spectator/test_registry.cpp index 657df44..65909f5 100644 --- a/spectator/test_registry.cpp +++ b/spectator/test_registry.cpp @@ -155,28 +155,27 @@ TEST(RegistryTest, GaugeWithId) TEST(RegistryTest, GaugeWithIdWithTtlSeconds) { - // WriterConfig writerConfig(WriterTypes::Memory); - // Config config(writerConfig, {{"extra-tags", "foo"}}); - // auto r = Registry(config); - - // auto g = r.gauge_with_id(r.new_id("gauge", {{"my-tags", "bar"}}), 120); - // EXPECT_TRUE(memoryWriter->IsEmpty()); - - // g->Set(42); - // EXPECT_EQ("g,120:gauge,extra-tags=foo,my-tags=bar:42", memoryWriter->LastLine()); + Config config(WriterConfig(WriterTypes::Memory), {{"extra-tags", "foo"}}); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); + + auto g = Registry::gauge_with_id(r.new_id("gauge", {{"my-tags", "bar"}}), 120); + EXPECT_TRUE(memoryWriter->IsEmpty()); + g.Set(42); + EXPECT_EQ("g,120:gauge,extra-tags=foo,my-tags=bar:42.000000\n", memoryWriter->LastLine()); } -// TEST_F(RegistryTest, GaugeWithTtlSeconds) { -// WriterConfig writerConfig(WriterTypes::Memory); -// Config config(writerConfig); -// auto r = Registry(config); +TEST(RegistryTest, GaugeWithTtlSeconds) { + Config config(WriterConfig(WriterTypes::Memory)); + auto r = Registry(config); + auto memoryWriter = static_cast(WriterTestHelper::GetImpl()); -// auto g = r.gauge("gauge", 120); -// EXPECT_TRUE(memoryWriter->IsEmpty()); + auto g = r.gauge("gauge", {}, 120); + EXPECT_TRUE(memoryWriter->IsEmpty()); -// g.Set(42); -// EXPECT_EQ("g,120:gauge:42", memoryWriter->LastLine()); -// } + g.Set(42); + EXPECT_EQ("g,120:gauge:42.000000\n", memoryWriter->LastLine()); +} TEST(RegistryTest, MaxGauge) {