17 #include <boost/utility/string_view_fwd.hpp>
20 #include <boost/algorithm/string/replace.hpp>
21 #include <boost/utility/string_view.hpp>
24 #include "hazelcast/client/client_config.h"
25 #include "hazelcast/client/client_properties.h"
26 #include "hazelcast/client/connection/ClientConnectionManagerImpl.h"
27 #include "hazelcast/client/connection/Connection.h"
28 #include "hazelcast/client/impl/metrics/metrics_compressor.h"
29 #include "hazelcast/client/impl/metrics/metric_descriptor.h"
30 #include "hazelcast/client/impl/statistics/Statistics.h"
31 #include "hazelcast/client/internal/nearcache/NearCache.h"
32 #include "hazelcast/client/internal/nearcache/NearCacheManager.h"
33 #include "hazelcast/client/monitor/impl/LocalMapStatsImpl.h"
34 #include "hazelcast/client/monitor/impl/NearCacheStatsImpl.h"
35 #include "hazelcast/client/protocol/codec/codecs.h"
36 #include "hazelcast/client/protocol/codec/codecs.h"
37 #include "hazelcast/client/spi/ClientContext.h"
38 #include "hazelcast/client/spi/impl/ClientExecutionServiceImpl.h"
39 #include "hazelcast/client/spi/impl/ClientInvocation.h"
40 #include "hazelcast/client/spi/lifecycle_service.h"
45 namespace statistics {
46 const std::string Statistics::NEAR_CACHE_CATEGORY_PREFIX(
"nc.");
48 Statistics::Statistics(spi::ClientContext &client_context) : client_context_(client_context),
50 client_context.get_client_properties()),
51 logger_(client_context.get_logger()),
52 periodic_stats_(*this) {
53 this->enabled_ = client_properties_.get_boolean(client_properties_.get_statistics_enabled());
56 void Statistics::start() {
61 int64_t periodSeconds = client_properties_.get_long(client_properties_.get_statistics_period_seconds());
62 if (periodSeconds <= 0) {
64 int64_t defaultValue = util::IOUtil::to_value<int64_t>(
65 client_properties_.get_statistics_period_seconds().get_default_value());
66 HZ_LOG(logger_, warning,
67 boost::str(boost::format(
68 "Provided client statistics %1% cannot be less than or equal to 0. "
69 "You provided %2% seconds as the configuration. "
70 "Client will use the default value of %3% instead.")
71 % client_properties_.get_statistics_period_seconds().get_name()
72 % periodSeconds % defaultValue)
74 periodSeconds = defaultValue;
77 schedule_periodic_statistics_send_task(periodSeconds);
80 boost::str(boost::format(
"Client statistics is enabled with period %1% seconds.")
85 void Statistics::shutdown() {
86 if (send_task_timer_) {
87 boost::system::error_code ignored;
88 send_task_timer_->cancel(ignored);
92 void Statistics::schedule_periodic_statistics_send_task(int64_t period_seconds) {
93 send_task_timer_ = client_context_.get_client_execution_service().schedule_with_repetition([=]() {
94 if (!client_context_.get_lifecycle_service().is_running()) {
98 auto collection_timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
99 std::chrono::system_clock::now().time_since_epoch()).count();
100 std::shared_ptr<connection::Connection> connection = get_connection();
102 HZ_LOG(logger_, finest,
"Cannot send client statistics to the server. No connection found.");
106 std::ostringstream stats;
107 metrics::metrics_compressor metrics_comp;
109 periodic_stats_.fill_metrics(stats, metrics_comp, connection);
111 periodic_stats_.add_near_cache_stats(stats, metrics_comp);
114 send_stats(collection_timestamp, stats.str(), metrics_comp.get_blob(), connection);
115 }, std::chrono::seconds(0), std::chrono::seconds(period_seconds));
118 std::shared_ptr<connection::Connection> Statistics::get_connection() {
119 return client_context_.get_connection_manager().get_random_connection();
122 void Statistics::send_stats(int64_t timestamp,
const std::string &new_stats,
123 const std::vector<byte> metrics_blob,
124 const std::shared_ptr<connection::Connection> &connection) {
125 auto request = protocol::codec::client_statistics_encode(timestamp, new_stats, metrics_blob);
127 spi::impl::ClientInvocation::create(client_context_, request,
"", connection)->invoke().get();
128 }
catch (exception::iexception &e) {
130 HZ_LOG(logger_, finest,
131 boost::str(boost::format(
"Could not send stats %1%") % e)
136 void Statistics::PeriodicStatistics::fill_metrics(std::ostringstream &stats,
137 metrics::metrics_compressor &compressor,
138 const std::shared_ptr<connection::Connection> &connection) {
139 stats <<
"lastStatisticsCollectionTime" << KEY_VALUE_SEPARATOR << util::current_time_millis();
140 add_stat(stats,
"enterprise",
false);
141 add_stat(stats,
"clientType", protocol::ClientTypes::CPP);
142 add_stat(stats,
"clientVersion", HAZELCAST_VERSION);
143 add_stat(stats,
"clusterConnectionTimestamp", std::chrono::duration_cast<std::chrono::milliseconds>(
144 connection->get_start_time().time_since_epoch()).count());
146 auto localSocketAddress = connection->get_local_socket_address();
147 stats << STAT_SEPARATOR <<
"clientAddress" << KEY_VALUE_SEPARATOR;
148 if (localSocketAddress) {
149 stats << localSocketAddress->get_host() <<
":" << localSocketAddress->get_port();
152 add_stat(stats,
"clientName", statistics_.client_context_.get_name());
154 auto credential = statistics_.client_context_.get_client_config().get_credentials();
156 add_stat(stats,
"credentials.principal", credential->name());
159 auto hw_concurrency = std::thread::hardware_concurrency();
161 add_stat(stats,
"runtime.availableProcessors", hw_concurrency);
162 compressor.add_long({
"runtime",
"availableProcessors", metrics::probe_unit::COUNT}, hw_concurrency);
167 void Statistics::PeriodicStatistics::add_near_cache_stats(std::ostringstream &stats,
168 metrics::metrics_compressor &compressor) {
169 for (
auto near_cache : statistics_.client_context_.get_near_cache_manager().list_all_near_caches()) {
170 std::string nc_name = near_cache->get_name();
172 std::ostringstream nc_name_with_prefix_strm;
173 get_name_with_prefix(nc_name, nc_name_with_prefix_strm);
174 nc_name_with_prefix_strm <<
'.';
175 std::string nc_name_with_prefix = nc_name_with_prefix_strm.str();
177 auto nc_stats = std::static_pointer_cast<monitor::impl::NearCacheStatsImpl>(
178 near_cache->get_near_cache_stats());
180 add_near_cache_metric(stats,
185 nc_stats->get_creation_time(),
186 metrics::probe_unit::MS);
188 add_near_cache_metric(stats,
193 nc_stats->get_evictions(),
194 metrics::probe_unit::COUNT);
196 add_near_cache_metric(stats,
201 nc_stats->get_hits(),
202 metrics::probe_unit::COUNT);
204 add_near_cache_metric(stats,
206 "lastPersistenceDuration",
209 nc_stats->get_last_persistence_duration(),
210 metrics::probe_unit::MS);
212 add_near_cache_metric(stats,
214 "lastPersistenceKeyCount",
217 nc_stats->get_last_persistence_key_count(),
218 metrics::probe_unit::COUNT);
220 add_near_cache_metric(stats,
222 "lastPersistenceTime",
225 nc_stats->get_last_persistence_time(),
226 metrics::probe_unit::MS);
228 add_near_cache_metric(stats,
230 "lastPersistenceWrittenBytes",
233 nc_stats->get_last_persistence_written_bytes(),
234 metrics::probe_unit::BYTES);
236 add_near_cache_metric(stats,
241 nc_stats->get_misses(),
242 metrics::probe_unit::COUNT);
244 add_near_cache_metric(stats,
249 nc_stats->get_owned_entry_count(),
250 metrics::probe_unit::COUNT);
252 add_near_cache_metric(stats,
257 nc_stats->get_expirations(),
258 metrics::probe_unit::COUNT);
260 add_near_cache_metric(stats,
265 nc_stats->get_invalidations(),
266 metrics::probe_unit::COUNT);
268 add_near_cache_metric(stats,
270 "invalidationRequests",
273 nc_stats->get_invalidation_requests(),
274 metrics::probe_unit::COUNT);
276 add_near_cache_metric(stats,
278 "ownedEntryMemoryCost",
281 nc_stats->get_owned_entry_memory_cost(),
282 metrics::probe_unit::BYTES);
287 void Statistics::PeriodicStatistics::add_near_cache_metric(std::ostringstream &stats,
288 metrics::metrics_compressor &compressor,
289 const std::string &metric,
290 const std::string &near_cache_name,
291 const std::string &near_cache_name_with_prefix,
293 metrics::probe_unit unit) {
295 metrics::metric_descriptor desc{
"nearcache", metric,
"name", near_cache_name, unit };
296 compressor.add_long(desc, value);
299 add_stat(stats, near_cache_name_with_prefix, metric, value);
302 Statistics::PeriodicStatistics::PeriodicStatistics(Statistics &statistics) : statistics_(statistics) {}
304 std::string Statistics::escape_special_characters(std::string &name) {
305 boost::replace_all(name,
",",
"\\,");
306 boost::replace_all(name,
"=",
"\\=");
307 boost::replace_all(name,
"\\",
"\\\\");
309 return name[0] ==
'/' ? name.substr(1) : name;
313 Statistics::PeriodicStatistics::get_name_with_prefix(std::string &name, std::ostringstream &out) {
314 out << NEAR_CACHE_CATEGORY_PREFIX << Statistics::escape_special_characters(name);
318 void Statistics::PeriodicStatistics::add_stat(std::ostringstream &stats,
const std::string &name,
320 stats << STAT_SEPARATOR << name << KEY_VALUE_SEPARATOR << (value ?
"true" :
"false");
327 const int64_t local_instance_stats::STAT_NOT_AVAILABLE = -99L;
330 LocalMapStatsImpl::LocalMapStatsImpl() =
default;
332 LocalMapStatsImpl::LocalMapStatsImpl(
const std::shared_ptr<monitor::near_cache_stats> &s) : near_cache_stats_(s) {}
334 std::shared_ptr<monitor::near_cache_stats> LocalMapStatsImpl::get_near_cache_stats()
const {
335 return near_cache_stats_;
338 NearCacheStatsImpl::NearCacheStatsImpl() : creation_time_(util::current_time_millis()),
339 owned_entry_count_(0),
340 owned_entry_memory_cost_(0),
346 invalidation_requests_(0),
347 persistence_count_(0),
348 last_persistence_time_(0),
349 last_persistence_duration_(0),
350 last_persistence_written_bytes_(0),
351 last_persistence_key_count_(0),
352 last_persistence_failure_(
"") {
355 int64_t NearCacheStatsImpl::get_creation_time() {
356 return creation_time_;
359 int64_t NearCacheStatsImpl::get_owned_entry_count() {
360 return owned_entry_count_;
363 void NearCacheStatsImpl::set_owned_entry_count(int64_t owned_entry_count) {
364 this->owned_entry_count_ = owned_entry_count;
367 void NearCacheStatsImpl::increment_owned_entry_count() {
368 ++owned_entry_count_;
371 void NearCacheStatsImpl::decrement_owned_entry_count() {
372 --owned_entry_count_;
375 int64_t NearCacheStatsImpl::get_owned_entry_memory_cost() {
376 return owned_entry_memory_cost_;
379 void NearCacheStatsImpl::set_owned_entry_memory_cost(int64_t owned_entry_memory_cost) {
380 this->owned_entry_memory_cost_ = owned_entry_memory_cost;
383 void NearCacheStatsImpl::increment_owned_entry_memory_cost(int64_t owned_entry_memory_cost) {
384 this->owned_entry_memory_cost_ += owned_entry_memory_cost;
387 void NearCacheStatsImpl::decrement_owned_entry_memory_cost(int64_t owned_entry_memory_cost) {
388 this->owned_entry_memory_cost_ -= owned_entry_memory_cost;
391 int64_t NearCacheStatsImpl::get_hits() {
396 void NearCacheStatsImpl::set_hits(int64_t hits) {
400 void NearCacheStatsImpl::increment_hits() {
404 int64_t NearCacheStatsImpl::get_misses() {
409 void NearCacheStatsImpl::set_misses(int64_t misses) {
410 this->misses_ = misses;
413 void NearCacheStatsImpl::increment_misses() {
417 double NearCacheStatsImpl::get_ratio() {
418 if (misses_ == (int64_t) 0) {
419 if (hits_ == (int64_t) 0) {
420 return std::numeric_limits<double>::signaling_NaN();
422 return std::numeric_limits<double>::infinity();
425 return ((
double) hits_ / misses_) * PERCENTAGE;
429 int64_t NearCacheStatsImpl::get_evictions() {
433 void NearCacheStatsImpl::increment_evictions() {
437 int64_t NearCacheStatsImpl::get_expirations() {
441 void NearCacheStatsImpl::increment_expirations() {
445 int64_t NearCacheStatsImpl::get_invalidations() {
446 return invalidations_.load();
449 void NearCacheStatsImpl::increment_invalidations() {
453 int64_t NearCacheStatsImpl::get_invalidation_requests() {
454 return invalidation_requests_.load();
457 void NearCacheStatsImpl::increment_invalidation_requests() {
458 ++invalidation_requests_;
461 void NearCacheStatsImpl::reset_invalidation_events() {
462 invalidation_requests_ = 0;
465 int64_t NearCacheStatsImpl::get_persistence_count() {
466 return persistence_count_;
469 void NearCacheStatsImpl::add_persistence(int64_t duration, int32_t written_bytes, int32_t key_count) {
470 ++persistence_count_;
471 last_persistence_time_ = util::current_time_millis();
472 last_persistence_duration_ = duration;
473 last_persistence_written_bytes_ = written_bytes;
474 last_persistence_key_count_ = key_count;
475 last_persistence_failure_ =
"";
478 int64_t NearCacheStatsImpl::get_last_persistence_time() {
479 return last_persistence_time_;
482 int64_t NearCacheStatsImpl::get_last_persistence_duration() {
483 return last_persistence_duration_;
486 int64_t NearCacheStatsImpl::get_last_persistence_written_bytes() {
487 return last_persistence_written_bytes_;
490 int64_t NearCacheStatsImpl::get_last_persistence_key_count() {
491 return last_persistence_key_count_;
494 std::string NearCacheStatsImpl::get_last_persistence_failure() {
495 return last_persistence_failure_;
498 std::string NearCacheStatsImpl::to_string() {
499 std::ostringstream out;
500 std::string failureString = last_persistence_failure_;
501 out <<
"NearCacheStatsImpl{"
502 <<
"ownedEntryCount=" << owned_entry_count_
503 <<
", ownedEntryMemoryCost=" << owned_entry_memory_cost_
504 <<
", creationTime=" << creation_time_
505 <<
", hits=" << hits_
506 <<
", misses=" << misses_
507 <<
", ratio=" << std::setprecision(1) << get_ratio()
508 <<
", evictions=" << evictions_
509 <<
", expirations=" << expirations_
510 <<
", invalidations=" << invalidations_.load()
511 <<
", invalidationRequests=" << invalidation_requests_.load()
512 <<
", lastPersistenceTime=" << last_persistence_time_
513 <<
", persistenceCount=" << persistence_count_
514 <<
", lastPersistenceDuration=" << last_persistence_duration_
515 <<
", lastPersistenceWrittenBytes=" << last_persistence_written_bytes_
516 <<
", lastPersistenceKeyCount=" << last_persistence_key_count_
517 <<
", lastPersistenceFailure='" << failureString <<
"'"
523 const double NearCacheStatsImpl::PERCENTAGE = 100.0;