Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
832483e
Spectator2.0 (#121)
ecbadeaux Jun 10, 2025
1708a76
save work
ecbadeaux Jun 11, 2025
369d13d
save work
ecbadeaux Jun 11, 2025
a6591ad
clean up meter
ecbadeaux Jun 11, 2025
051147b
fix docker build
ecbadeaux Jun 11, 2025
0c3a439
Reformat and add clang settings
ecbadeaux Jun 16, 2025
174bcdc
reorg meter_id
ecbadeaux Jun 16, 2025
01c14f4
reorg config
ecbadeaux Jun 16, 2025
be94523
remove base folders
ecbadeaux Jun 16, 2025
b5c092e
remove excess folders writer_config
ecbadeaux Jun 16, 2025
27253bd
flatten project
ecbadeaux Jun 16, 2025
a20e641
Add buffering
ecbadeaux Jun 16, 2025
9e0e02e
fix vexing error
ecbadeaux Jun 17, 2025
18baa1d
resolve clion errors
ecbadeaux Jun 17, 2025
46e7b91
more clion fixes
ecbadeaux Jun 17, 2025
fd1652d
Clang Tidy improvements
ecbadeaux Jun 18, 2025
985989d
more clang tidy fixes
ecbadeaux Jun 18, 2025
71c8205
add performance test
ecbadeaux Jun 18, 2025
4655236
update tests
ecbadeaux Jun 18, 2025
06ab80e
get udp perf test working
Jun 18, 2025
3c0051c
add uds test and buffering tests
ecbadeaux Jun 19, 2025
43fcde7
improve line construction for meters
ecbadeaux Jun 19, 2025
e12c631
update performnace tests
ecbadeaux Jun 19, 2025
9d39689
add threading performance test
ecbadeaux Jun 19, 2025
42be0f4
fix whitepsace check in tags
ecbadeaux Jun 19, 2025
823be68
remove duplicate function
ecbadeaux Jun 21, 2025
1f7a1b6
Changes required while modifying atlas
ecbadeaux Jun 26, 2025
c648c0b
save work
ecbadeaux Jun 27, 2025
6e255d7
fix header file naming
ecbadeaux Jun 30, 2025
052e52c
last fixes
ecbadeaux Jul 3, 2025
f322f86
fix log
ecbadeaux Jul 3, 2025
a76292a
update writer wrapper
ecbadeaux Jul 3, 2025
d396b85
add workflow
ecbadeaux Jul 7, 2025
d5786eb
update build script
ecbadeaux Jul 7, 2025
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
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ jobs:
path: |
/home/runner/.conan2
/home/runner/work/spectator-cpp/spectator-cpp/cmake-build
key: ${{ steps.conan-cache-restore.outputs.cache-primary-key }}
key: ${{ steps.conan-cache-restore.outputs.cache-primary-key }}
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/
73 changes: 12 additions & 61 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,70 +1,21 @@
cmake_minimum_required(VERSION 3.23)

project(spectator-cpp)
cmake_minimum_required(VERSION 3.15)
project(spectator-cpp 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>")
add_compile_options(-pedantic -Werror -Wall -Wno-missing-braces -fno-omit-frame-pointer)

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)

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")

#-- 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
81 changes: 5 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,87 +2,16 @@

# 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++
#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

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
fills up, the `Publisher` will not send nay meters to the sidecar. Therefore, if your application doesn't emit
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.

Expand All @@ -106,4 +35,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`
20 changes: 8 additions & 12 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ NC="\033[0m"
if [[ "$1" == "clean" ]]; then
echo -e "${BLUE}==== clean ====${NC}"
rm -rf "$BUILD_DIR"
rm -f spectator/*.inc
if [[ "$2" == "--confirm" ]]; then
# remove all packages from the conan cache, to allow swapping between Release/Debug builds
conan remove "*" --confirm
fi
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

Expand All @@ -46,14 +46,10 @@ 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
else
conan install . --output-folder="$BUILD_DIR" --build=missing --settings=build_type="$BUILD_TYPE"
fi
conan install . --output-folder="$BUILD_DIR" --build="*" --settings=build_type="$BUILD_TYPE"
fi

pushd $BUILD_DIR
pushd "$BUILD_DIR"

echo -e "${BLUE}==== configure conan environment to access tools ====${NC}"
source conanbuild.sh
Expand All @@ -63,7 +59,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 .
Expand All @@ -73,4 +69,4 @@ if [[ "$1" != "skiptest" ]]; then
GTEST_COLOR=1 ctest --verbose
fi

popd
popd
Loading
Loading