Skip to content

Spectator 2.0 #122

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
Expand All @@ -20,22 +19,22 @@ 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
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: Attach
BreakBeforeBraces: Allman
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
ColumnLimit: 100
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
Expand All @@ -53,7 +52,7 @@ IncludeCategories:
- Regex: '.*'
Priority: 3
IndentCaseLabels: true
IndentWidth: 2
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
Expand Down Expand Up @@ -84,5 +83,4 @@ SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
TabWidth: 8
UseTab: Never
...
UseTab: Never
43 changes: 0 additions & 43 deletions .github/workflows/build.yml

This file was deleted.

5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
.DS_Store
.idea/
.vscode/
CMakeUserPresets.json
cmake-build/
cmake-build-debug/
cmake-build-release/
conan_provider.cmake
spectator/valid_chars.inc
venv/
venv/
79 changes: 17 additions & 62 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,70 +1,25 @@
cmake_minimum_required(VERSION 3.23)

project(spectator-cpp)
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 "$<$<CONFIG:Debug>:-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
)

#-- generator tools
add_executable(gen_valid_chars "tools/gen_valid_chars.cc")
# Build tests if enabled
if(BUILD_TESTS)
enable_testing()
endif()

#-- 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
)
# Add subdirectories
add_subdirectory(libs)
add_subdirectory(spectator)
add_subdirectory(performance_tests)
32 changes: 32 additions & 0 deletions Dockerfiles/README.md
Original file line number Diff line number Diff line change
@@ -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 spectator-cpp-image
./build.sh
```

## Windows

##### Warning:

- Start `Docker` before opening `Powershell`

```shell
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
```
26 changes: 26 additions & 0 deletions Dockerfiles/Ubuntu.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# 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 \
build-essential

# 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"]
2 changes: 2 additions & 0 deletions Dockerfiles/Ubuntu.Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Ignore copying the default build folder if it exists
cmake-build/
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 1 addition & 1 deletion OSSMETADATA
Original file line number Diff line number Diff line change
@@ -1 +1 @@
osslifecycle=active
osslifecycle=active
69 changes: 2 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,72 +8,7 @@ consists of a thin client designed to send metrics through [spectatord](https://
## Instrumenting Code

```C++
#include <spectator/registry.h>

// 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<spectator::Id> request_count_id_;
std::shared_ptr<spectator::Timer> request_latency_;
std::shared_ptr<spectator::DistributionSummary> response_size_;
};

Request get_next_request() {
return Request{"US"};
}

int main() {
auto logger = spdlog::stdout_color_mt("console");
std::unordered_map<std::string, std::string> 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{&registry};

for (auto i = 1; i <= 3; ++i) {
// get a request
auto req = get_next_request();
server.Handle(req);
}
}
```

## High-Volume Publishing
Expand All @@ -82,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.

Expand All @@ -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`
Loading