diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cf201ce38f..e4093f4de2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,11 +48,18 @@ include(LoggingHelper) option(OPTIONS_ENABLE_CCACHE "Enable ccache" OFF) option(OPTIONS_ENABLE_SCCACHE "Use sccache to speed up compilation process" OFF) option(OPTIONS_ENABLE_IPO "Check and Enable interprocedural optimization (IPO/LTO)" ON) +option(FEATURE_METRICS "Enable metrics feature" OFF) # ***************************************************************************** # Options Code # ***************************************************************************** +if(FEATURE_METRIC) + log_option_enabled("metrics") +else () + log_option_disabled("metrics") +endif () + # === CCACHE === if(OPTIONS_ENABLE_CCACHE) find_program(CCACHE ccache) diff --git a/cmake/modules/BaseConfig.cmake b/cmake/modules/BaseConfig.cmake index 6a8ce69ed4b..7e3f6404b3f 100644 --- a/cmake/modules/BaseConfig.cmake +++ b/cmake/modules/BaseConfig.cmake @@ -32,8 +32,10 @@ find_package(absl CONFIG REQUIRED) find_package(asio CONFIG REQUIRED) find_package(eventpp CONFIG REQUIRED) find_package(magic_enum CONFIG REQUIRED) -find_package(opentelemetry-cpp CONFIG REQUIRED) -find_package(prometheus-cpp CONFIG REQUIRED) +if(FEATURE_METRICS) + find_package(opentelemetry-cpp CONFIG REQUIRED) + find_package(prometheus-cpp CONFIG REQUIRED) +endif() find_package(mio REQUIRED) find_package(pugixml CONFIG REQUIRED) find_package(spdlog REQUIRED) diff --git a/cmake/modules/CanaryLib.cmake b/cmake/modules/CanaryLib.cmake index 270bbf59a99..a3f5410b9d8 100644 --- a/cmake/modules/CanaryLib.cmake +++ b/cmake/modules/CanaryLib.cmake @@ -105,17 +105,25 @@ target_link_libraries(${PROJECT_NAME}_lib unofficial::argon2::libargon2 unofficial::libmariadb unofficial::mariadbclient - opentelemetry-cpp::common - opentelemetry-cpp::metrics - opentelemetry-cpp::api - opentelemetry-cpp::ext - opentelemetry-cpp::sdk - opentelemetry-cpp::logs - opentelemetry-cpp::ostream_metrics_exporter - opentelemetry-cpp::prometheus_exporter protobuf ) +if(FEATURE_METRICS) + add_definitions(-DFEATURE_METRICS) + + target_link_libraries(${PROJECT_NAME}_lib + PUBLIC + opentelemetry-cpp::common + opentelemetry-cpp::metrics + opentelemetry-cpp::api + opentelemetry-cpp::ext + opentelemetry-cpp::sdk + opentelemetry-cpp::logs + opentelemetry-cpp::ostream_metrics_exporter + opentelemetry-cpp::prometheus_exporter + ) +endif() + if(CMAKE_BUILD_TYPE MATCHES Debug) target_link_libraries(${PROJECT_NAME}_lib PUBLIC ${ZLIB_LIBRARY_DEBUG}) else() diff --git a/src/canary_server.cpp b/src/canary_server.cpp index 56cd53bf567..0961bc93fde 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -61,6 +61,7 @@ int CanaryServer::run() { loadConfigLua(); logger.info("Server protocol: {}.{}{}", CLIENT_VERSION_UPPER, CLIENT_VERSION_LOWER, g_configManager().getBoolean(OLD_PROTOCOL, __FUNCTION__) ? " and 10x allowed!" : ""); +#ifdef FEATURE_METRICS metrics::Options metricsOptions; metricsOptions.enablePrometheusExporter = g_configManager().getBoolean(METRICS_ENABLE_PROMETHEUS, __FUNCTION__); if (metricsOptions.enablePrometheusExporter) { @@ -71,7 +72,7 @@ int CanaryServer::run() { metricsOptions.ostreamOptions.export_interval_millis = std::chrono::milliseconds(g_configManager().getNumber(METRICS_OSTREAM_INTERVAL, __FUNCTION__)); } g_metrics().init(metricsOptions); - +#endif rsa.start(); initializeDatabase(); loadModules(); diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 402c6a34a79..55709c59ac3 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,6 +1,9 @@ target_sources(${PROJECT_NAME}_lib PRIVATE di/soft_singleton.cpp logging/log_with_spd_log.cpp - metrics/metrics.cpp thread/thread_pool.cpp ) + +if(FEATURE_METRICS) + target_sources(${PROJECT_NAME}_lib PRIVATE metrics/metrics.cpp) +endif() diff --git a/src/lib/metrics/metrics.cpp b/src/lib/metrics/metrics.cpp index 2a65e9a7d5d..cf11060125a 100644 --- a/src/lib/metrics/metrics.cpp +++ b/src/lib/metrics/metrics.cpp @@ -1,3 +1,4 @@ +#ifdef FEATURE_METRICS /** * Canary - A free and open-source MMORPG server emulator * Copyright (©) 2019-2024 OpenTibiaBR @@ -7,8 +8,8 @@ * Website: https://docs.opentibiabr.com/ */ -#include "metrics.hpp" -#include "lib/di/container.hpp" + #include "metrics.hpp" + #include "lib/di/container.hpp" using namespace metrics; @@ -41,7 +42,7 @@ void Metrics::init(Options opts) { initHistograms(); } -void Metrics ::initHistograms() { +void Metrics::initHistograms() { for (auto name : latencyNames) { auto instrumentSelector = metrics_sdk::InstrumentSelectorFactory::Create(metrics_sdk::InstrumentType::kHistogram, name, "us"); auto meterSelector = metrics_sdk::MeterSelectorFactory::Create("performance", otelVersion, otelSchema); @@ -108,3 +109,5 @@ void ScopedLatency::stop() { auto attrskv = opentelemetry::common::KeyValueIterableView { attrs }; histogram->Record(elapsed, attrskv, context); } + +#endif // FEATURE_METRICS diff --git a/src/lib/metrics/metrics.hpp b/src/lib/metrics/metrics.hpp index 0d8c291dfbe..279ea5f91c5 100644 --- a/src/lib/metrics/metrics.hpp +++ b/src/lib/metrics/metrics.hpp @@ -9,43 +9,29 @@ #pragma once -#include "game/scheduling/dispatcher.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#ifdef FEATURE_METRICS + #include "game/scheduling/dispatcher.hpp" + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include namespace metrics_sdk = opentelemetry::sdk::metrics; namespace common = opentelemetry::common; namespace metrics_exporter = opentelemetry::exporter::metrics; namespace metrics_api = opentelemetry::metrics; -constexpr std::string_view methodName(const char* s) { - std::string_view prettyFunction(s); - size_t bracket = prettyFunction.rfind("("); - size_t space = prettyFunction.rfind(" ", bracket) + 1; - return prettyFunction.substr(space, bracket - space); -} - -#if defined(__GNUC__) || defined(__clang__) - #define __METHOD_NAME__ methodName(__PRETTY_FUNCTION__) -#elif defined(_MSC_VER) - #define __METHOD_NAME__ methodName(__FUNCSIG__) -#else - #error "Compiler not supported" -#endif - namespace metrics { using Meter = opentelemetry::nostd::shared_ptr; @@ -85,12 +71,12 @@ namespace metrics { bool stopped { false }; }; -#define DEFINE_LATENCY_CLASS(class_name, histogram_name, category) \ - class class_name##_latency final : public ScopedLatency { \ - public: \ - class_name##_latency(std::string_view name) : \ - ScopedLatency(name, histogram_name "_latency", category) { } \ - } + #define DEFINE_LATENCY_CLASS(class_name, histogram_name, category) \ + class class_name##_latency final : public ScopedLatency { \ + public: \ + class_name##_latency(std::string_view name) : \ + ScopedLatency(name, histogram_name "_latency", category) { } \ + } DEFINE_LATENCY_CLASS(method, "method", "method"); DEFINE_LATENCY_CLASS(lua, "lua", "scope"); @@ -170,3 +156,70 @@ namespace metrics { constexpr auto g_metrics = metrics::Metrics::getInstance; + +#else // FEATURE_METRICS + + #include "lib/di/container.hpp" + +struct Options { + bool enablePrometheusExporter; + bool enableOStreamExporter; +}; + +class ScopedLatency { +public: + explicit ScopedLatency([[maybe_unused]] std::string_view name, [[maybe_unused]] const std::string &histogramName, [[maybe_unused]] const std::string &scopeKey) {}; + explicit ScopedLatency([[maybe_unused]] std::string_view name, [[maybe_unused]] std::set &histogram, [[maybe_unused]] const std::map &attrs = {}, [[maybe_unused]] const std::string &context = std::string()) {}; + + void stop() {}; + + ~ScopedLatency() = default; +}; + +namespace metrics { + #define DEFINE_LATENCY_CLASS(class_name, histogram_name, category) \ + class class_name##_latency final : public ScopedLatency { \ + public: \ + class_name##_latency(std::string_view name) : \ + ScopedLatency(name, histogram_name "_latency", category) { } \ + } + + DEFINE_LATENCY_CLASS(method, "method", "method"); + DEFINE_LATENCY_CLASS(lua, "lua", "scope"); + DEFINE_LATENCY_CLASS(query, "query", "truncated_query"); + DEFINE_LATENCY_CLASS(task, "task", "task"); + DEFINE_LATENCY_CLASS(lock, "lock", "scope"); + + const std::vector latencyNames { + "method_latency", + "lua_latency", + "query_latency", + "task_latency", + "lock_latency", + }; + + class Metrics final { + public: + Metrics() = default; + ~Metrics() = default; + + void init([[maybe_unused]] Options opts) {}; + void initHistograms() {}; + void shutdown() {}; + + static Metrics &getInstance() { + return inject(); + }; + + void addCounter([[maybe_unused]] std::string_view name, [[maybe_unused]] double value, [[maybe_unused]] const std::map &attrs = {}) { } + + void addUpDownCounter([[maybe_unused]] std::string_view name, [[maybe_unused]] int value, [[maybe_unused]] const std::map &attrs = {}) { } + + friend class ScopedLatency; + }; +} + +constexpr auto g_metrics + = metrics::Metrics::getInstance; + +#endif // FEATURE_METRICS diff --git a/src/pch.hpp b/src/pch.hpp index 7c38a99ee94..e69c27016a4 100644 --- a/src/pch.hpp +++ b/src/pch.hpp @@ -170,3 +170,18 @@ struct fmt::formatter, char>> : formatter< #include #include "lua/global/shared_object.hpp" + +constexpr std::string_view methodName(const char* s) { + std::string_view prettyFunction(s); + size_t bracket = prettyFunction.rfind('('); + size_t space = prettyFunction.rfind(' ', bracket) + 1; + return prettyFunction.substr(space, bracket - space); +} + +#if defined(__GNUC__) || defined(__clang__) + #define __METHOD_NAME__ methodName(__PRETTY_FUNCTION__) +#elif defined(_MSC_VER) + #define __METHOD_NAME__ methodName(__FUNCSIG__) +#else + #error "Compiler not supported" +#endif diff --git a/vcpkg.json b/vcpkg.json index a0bc4a0332b..dda054f3774 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -12,14 +12,6 @@ "luajit", "magic-enum", "mio", - { - "name": "opentelemetry-cpp", - "default-features": true, - "features": [ - "otlp-http", - "prometheus" - ] - }, "parallel-hashmap", "protobuf", "pugixml",