34 #include <boost/algorithm/string/replace.hpp>
36 #include "hazelcast/client/impl/statistics/Statistics.h"
37 #include "hazelcast/client/spi/ClientContext.h"
38 #include "hazelcast/client/client_properties.h"
39 #include "hazelcast/client/spi/impl/ClientExecutionServiceImpl.h"
40 #include "hazelcast/client/spi/impl/ClientInvocation.h"
41 #include "hazelcast/client/spi/lifecycle_service.h"
42 #include "hazelcast/client/connection/Connection.h"
43 #include "hazelcast/client/connection/ClientConnectionManagerImpl.h"
44 #include "hazelcast/client/protocol/codec/codecs.h"
45 #include "hazelcast/client/protocol/codec/codecs.h"
46 #include "hazelcast/client/internal/nearcache/NearCache.h"
47 #include "hazelcast/client/internal/nearcache/NearCacheManager.h"
48 #include "hazelcast/client/monitor/impl/NearCacheStatsImpl.h"
49 #include "hazelcast/client/monitor/impl/LocalMapStatsImpl.h"
50 #include "hazelcast/client/client_config.h"
55 namespace statistics {
56 const std::string Statistics::NEAR_CACHE_CATEGORY_PREFIX(
"nc.");
58 Statistics::Statistics(spi::ClientContext &client_context) : client_context_(client_context),
60 client_context.get_client_properties()),
61 logger_(client_context.get_logger()),
62 periodic_stats_(*this) {
63 this->enabled_ = client_properties_.get_boolean(client_properties_.get_statistics_enabled());
66 void Statistics::start() {
71 int64_t periodSeconds = client_properties_.get_long(client_properties_.get_statistics_period_seconds());
72 if (periodSeconds <= 0) {
74 int64_t defaultValue = util::IOUtil::to_value<int64_t>(
75 client_properties_.get_statistics_period_seconds().get_default_value());
76 HZ_LOG(logger_, warning,
77 boost::str(boost::format(
78 "Provided client statistics %1% cannot be less than or equal to 0. "
79 "You provided %2% seconds as the configuration. "
80 "Client will use the default value of %3% instead.")
81 % client_properties_.get_statistics_period_seconds().get_name()
82 % periodSeconds % defaultValue)
84 periodSeconds = defaultValue;
87 schedule_periodic_statistics_send_task(periodSeconds);
90 boost::str(boost::format(
"Client statistics is enabled with period %1% seconds.")
95 void Statistics::shutdown() {
96 if (send_task_timer_) {
97 boost::system::error_code ignored;
98 send_task_timer_->cancel(ignored);
102 void Statistics::schedule_periodic_statistics_send_task(int64_t period_seconds) {
103 send_task_timer_ = client_context_.get_client_execution_service().schedule_with_repetition([=]() {
104 if (!client_context_.get_lifecycle_service().is_running()) {
108 auto collection_timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
109 std::chrono::system_clock::now().time_since_epoch()).count();
110 std::shared_ptr<connection::Connection> connection = get_connection();
112 HZ_LOG(logger_, finest,
"Cannot send client statistics to the server. No connection found.");
116 std::ostringstream stats;
118 periodic_stats_.fill_metrics(stats, connection);
120 periodic_stats_.add_near_cache_stats(stats);
122 send_stats(collection_timestamp, stats.str(), connection);
123 }, std::chrono::seconds(0), std::chrono::seconds(period_seconds));
126 std::shared_ptr<connection::Connection> Statistics::get_connection() {
127 return client_context_.get_connection_manager().get_random_connection();
130 void Statistics::send_stats(int64_t timestamp,
const std::string &new_stats,
131 const std::shared_ptr<connection::Connection> &connection) {
133 auto request = protocol::codec::client_statistics_encode(timestamp, new_stats, std::vector<byte>());
135 spi::impl::ClientInvocation::create(client_context_, request,
"", connection)->invoke().get();
136 }
catch (exception::iexception &e) {
138 HZ_LOG(logger_, finest,
139 boost::str(boost::format(
"Could not send stats %1%") % e)
144 void Statistics::PeriodicStatistics::fill_metrics(std::ostringstream &stats,
145 const std::shared_ptr<connection::Connection> &connection) {
146 stats <<
"lastStatisticsCollectionTime" << KEY_VALUE_SEPARATOR << util::current_time_millis();
147 add_stat(stats,
"enterprise",
false);
148 add_stat(stats,
"clientType", protocol::ClientTypes::CPP);
149 add_stat(stats,
"clientVersion", HAZELCAST_VERSION);
150 add_stat(stats,
"clusterConnectionTimestamp", std::chrono::duration_cast<std::chrono::milliseconds>(
151 connection->get_start_time().time_since_epoch()).count());
153 auto localSocketAddress = connection->get_local_socket_address();
154 stats << STAT_SEPARATOR <<
"clientAddress" << KEY_VALUE_SEPARATOR;
155 if (localSocketAddress) {
156 stats << localSocketAddress->get_host() <<
":" << localSocketAddress->get_port();
159 add_stat(stats,
"clientName", statistics_.client_context_.get_name());
161 auto credential = statistics_.client_context_.get_client_config().get_credentials();
163 add_stat(stats,
"credentials.principal", credential->name());
167 void Statistics::PeriodicStatistics::add_near_cache_stats(std::ostringstream &stats) {
168 for (
auto nearCache : statistics_.client_context_.get_near_cache_manager().list_all_near_caches()) {
169 std::string nearCacheName = nearCache->get_name();
170 std::ostringstream nearCacheNameWithPrefix;
171 get_name_with_prefix(nearCacheName, nearCacheNameWithPrefix);
173 nearCacheNameWithPrefix <<
'.';
175 auto nearCacheStats = std::static_pointer_cast<monitor::impl::NearCacheStatsImpl>(nearCache->get_near_cache_stats());
177 std::string prefix = nearCacheNameWithPrefix.str();
179 add_stat(stats, prefix,
"creationTime", nearCacheStats->get_creation_time());
180 add_stat(stats, prefix,
"evictions", nearCacheStats->get_evictions());
181 add_stat(stats, prefix,
"hits", nearCacheStats->get_hits());
182 add_stat(stats, prefix,
"lastPersistenceDuration",
183 nearCacheStats->get_last_persistence_duration());
184 add_stat(stats, prefix,
"lastPersistenceKeyCount",
185 nearCacheStats->get_last_persistence_key_count());
186 add_stat(stats, prefix,
"lastPersistenceTime",
187 nearCacheStats->get_last_persistence_time());
188 add_stat(stats, prefix,
"lastPersistenceWrittenBytes",
189 nearCacheStats->get_last_persistence_written_bytes());
190 add_stat(stats, prefix,
"misses", nearCacheStats->get_misses());
191 add_stat(stats, prefix,
"ownedEntryCount", nearCacheStats->get_owned_entry_count());
192 add_stat(stats, prefix,
"expirations", nearCacheStats->get_expirations());
193 add_stat(stats, prefix,
"invalidations", nearCacheStats->get_invalidations());
194 add_stat(stats, prefix,
"invalidationRequests",
195 nearCacheStats->get_invalidation_requests());
196 add_stat(stats, prefix,
"ownedEntryMemoryCost",
197 nearCacheStats->get_owned_entry_memory_cost());
198 std::string persistenceFailure = nearCacheStats->get_last_persistence_failure();
199 if (!persistenceFailure.empty()) {
200 add_stat(stats, prefix,
"lastPersistenceFailure", persistenceFailure);
206 Statistics::PeriodicStatistics::PeriodicStatistics(Statistics &statistics) : statistics_(statistics) {}
208 std::string Statistics::escape_special_characters(std::string &name) {
209 boost::replace_all(name,
",",
"\\,");
210 boost::replace_all(name,
"=",
"\\=");
211 boost::replace_all(name,
"\\",
"\\\\");
213 return name[0] ==
'/' ? name.substr(1) : name;
217 Statistics::PeriodicStatistics::get_name_with_prefix(std::string &name, std::ostringstream &out) {
218 out << NEAR_CACHE_CATEGORY_PREFIX << Statistics::escape_special_characters(name);
222 void Statistics::PeriodicStatistics::add_stat(std::ostringstream &stats,
const std::string &name,
224 stats << STAT_SEPARATOR << name << KEY_VALUE_SEPARATOR << (value ?
"true" :
"false");
231 const int64_t local_instance_stats::STAT_NOT_AVAILABLE = -99L;
234 LocalMapStatsImpl::LocalMapStatsImpl() =
default;
236 LocalMapStatsImpl::LocalMapStatsImpl(
const std::shared_ptr<monitor::near_cache_stats> &s) : near_cache_stats_(s) {}
238 std::shared_ptr<monitor::near_cache_stats> LocalMapStatsImpl::get_near_cache_stats()
const {
239 return near_cache_stats_;
242 NearCacheStatsImpl::NearCacheStatsImpl() : creation_time_(util::current_time_millis()),
243 owned_entry_count_(0),
244 owned_entry_memory_cost_(0),
250 invalidation_requests_(0),
251 persistence_count_(0),
252 last_persistence_time_(0),
253 last_persistence_duration_(0),
254 last_persistence_written_bytes_(0),
255 last_persistence_key_count_(0),
256 last_persistence_failure_(
"") {
259 int64_t NearCacheStatsImpl::get_creation_time() {
260 return creation_time_;
263 int64_t NearCacheStatsImpl::get_owned_entry_count() {
264 return owned_entry_count_;
267 void NearCacheStatsImpl::set_owned_entry_count(int64_t owned_entry_count) {
268 this->owned_entry_count_ = owned_entry_count;
271 void NearCacheStatsImpl::increment_owned_entry_count() {
272 ++owned_entry_count_;
275 void NearCacheStatsImpl::decrement_owned_entry_count() {
276 --owned_entry_count_;
279 int64_t NearCacheStatsImpl::get_owned_entry_memory_cost() {
280 return owned_entry_memory_cost_;
283 void NearCacheStatsImpl::set_owned_entry_memory_cost(int64_t owned_entry_memory_cost) {
284 this->owned_entry_memory_cost_ = owned_entry_memory_cost;
287 void NearCacheStatsImpl::increment_owned_entry_memory_cost(int64_t owned_entry_memory_cost) {
288 this->owned_entry_memory_cost_ += owned_entry_memory_cost;
291 void NearCacheStatsImpl::decrement_owned_entry_memory_cost(int64_t owned_entry_memory_cost) {
292 this->owned_entry_memory_cost_ -= owned_entry_memory_cost;
295 int64_t NearCacheStatsImpl::get_hits() {
300 void NearCacheStatsImpl::set_hits(int64_t hits) {
304 void NearCacheStatsImpl::increment_hits() {
308 int64_t NearCacheStatsImpl::get_misses() {
313 void NearCacheStatsImpl::set_misses(int64_t misses) {
314 this->misses_ = misses;
317 void NearCacheStatsImpl::increment_misses() {
321 double NearCacheStatsImpl::get_ratio() {
322 if (misses_ == (int64_t) 0) {
323 if (hits_ == (int64_t) 0) {
324 return std::numeric_limits<double>::signaling_NaN();
326 return std::numeric_limits<double>::infinity();
329 return ((
double) hits_ / misses_) * PERCENTAGE;
333 int64_t NearCacheStatsImpl::get_evictions() {
337 void NearCacheStatsImpl::increment_evictions() {
341 int64_t NearCacheStatsImpl::get_expirations() {
345 void NearCacheStatsImpl::increment_expirations() {
349 int64_t NearCacheStatsImpl::get_invalidations() {
350 return invalidations_.load();
353 void NearCacheStatsImpl::increment_invalidations() {
357 int64_t NearCacheStatsImpl::get_invalidation_requests() {
358 return invalidation_requests_.load();
361 void NearCacheStatsImpl::increment_invalidation_requests() {
362 ++invalidation_requests_;
365 void NearCacheStatsImpl::reset_invalidation_events() {
366 invalidation_requests_ = 0;
369 int64_t NearCacheStatsImpl::get_persistence_count() {
370 return persistence_count_;
373 void NearCacheStatsImpl::add_persistence(int64_t duration, int32_t written_bytes, int32_t key_count) {
374 ++persistence_count_;
375 last_persistence_time_ = util::current_time_millis();
376 last_persistence_duration_ = duration;
377 last_persistence_written_bytes_ = written_bytes;
378 last_persistence_key_count_ = key_count;
379 last_persistence_failure_ =
"";
382 int64_t NearCacheStatsImpl::get_last_persistence_time() {
383 return last_persistence_time_;
386 int64_t NearCacheStatsImpl::get_last_persistence_duration() {
387 return last_persistence_duration_;
390 int64_t NearCacheStatsImpl::get_last_persistence_written_bytes() {
391 return last_persistence_written_bytes_;
394 int64_t NearCacheStatsImpl::get_last_persistence_key_count() {
395 return last_persistence_key_count_;
398 std::string NearCacheStatsImpl::get_last_persistence_failure() {
399 return last_persistence_failure_;
402 std::string NearCacheStatsImpl::to_string() {
403 std::ostringstream out;
404 std::string failureString = last_persistence_failure_;
405 out <<
"NearCacheStatsImpl{"
406 <<
"ownedEntryCount=" << owned_entry_count_
407 <<
", ownedEntryMemoryCost=" << owned_entry_memory_cost_
408 <<
", creationTime=" << creation_time_
409 <<
", hits=" << hits_
410 <<
", misses=" << misses_
411 <<
", ratio=" << std::setprecision(1) << get_ratio()
412 <<
", evictions=" << evictions_
413 <<
", expirations=" << expirations_
414 <<
", invalidations=" << invalidations_.load()
415 <<
", invalidationRequests=" << invalidation_requests_.load()
416 <<
", lastPersistenceTime=" << last_persistence_time_
417 <<
", persistenceCount=" << persistence_count_
418 <<
", lastPersistenceDuration=" << last_persistence_duration_
419 <<
", lastPersistenceWrittenBytes=" << last_persistence_written_bytes_
420 <<
", lastPersistenceKeyCount=" << last_persistence_key_count_
421 <<
", lastPersistenceFailure='" << failureString <<
"'"
427 const double NearCacheStatsImpl::PERCENTAGE = 100.0;