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)
49 : client_context_(client_context)
50 , client_properties_(client_context.get_client_properties())
51 , logger_(client_context.get_logger())
52 , periodic_stats_(*this)
54 this->enabled_ = client_properties_.get_boolean(
55 client_properties_.get_statistics_enabled());
65 int64_t periodSeconds = client_properties_.get_long(
66 client_properties_.get_statistics_period_seconds());
67 if (periodSeconds <= 0) {
69 int64_t defaultValue = util::IOUtil::to_value<int64_t>(
70 client_properties_.get_statistics_period_seconds()
71 .get_default_value());
76 boost::format(
"Provided client statistics %1% cannot be less than "
78 "You provided %2% seconds as the configuration. "
79 "Client will use the default value of %3% instead.") %
80 client_properties_.get_statistics_period_seconds().get_name() %
81 periodSeconds % defaultValue));
82 periodSeconds = defaultValue;
85 schedule_periodic_statistics_send_task(periodSeconds);
91 boost::format(
"Client statistics is enabled with period %1% seconds.") %
96 Statistics::shutdown()
98 if (send_task_timer_) {
99 boost::system::error_code ignored;
100 send_task_timer_->cancel(ignored);
105 Statistics::schedule_periodic_statistics_send_task(int64_t period_seconds)
108 client_context_.get_client_execution_service().schedule_with_repetition(
110 if (!client_context_.get_lifecycle_service().is_running()) {
114 auto collection_timestamp =
115 std::chrono::duration_cast<std::chrono::milliseconds>(
116 std::chrono::system_clock::now().time_since_epoch())
118 std::shared_ptr<connection::Connection> connection =
123 "Cannot send client statistics to the server. No "
124 "connection found.");
128 std::ostringstream stats;
129 metrics::metrics_compressor metrics_comp;
131 periodic_stats_.fill_metrics(stats, metrics_comp, connection);
133 periodic_stats_.add_near_cache_stats(stats, metrics_comp);
135 send_stats(collection_timestamp,
137 metrics_comp.get_blob(),
140 std::chrono::seconds(0),
141 std::chrono::seconds(period_seconds));
144 std::shared_ptr<connection::Connection>
145 Statistics::get_connection()
147 return client_context_.get_connection_manager().get_random_connection();
151 Statistics::send_stats(
153 const std::string& new_stats,
154 const std::vector<byte> metrics_blob,
155 const std::shared_ptr<connection::Connection>& connection)
157 auto request = protocol::codec::client_statistics_encode(
158 timestamp, new_stats, metrics_blob);
160 spi::impl::ClientInvocation::create(
161 client_context_, request,
"", connection)
164 }
catch (exception::iexception& e) {
168 boost::str(boost::format(
"Could not send stats %1%") % e));
173 Statistics::PeriodicStatistics::fill_metrics(
174 std::ostringstream& stats,
175 metrics::metrics_compressor& compressor,
176 const std::shared_ptr<connection::Connection>& connection)
178 stats <<
"lastStatisticsCollectionTime" << KEY_VALUE_SEPARATOR
179 << util::current_time_millis();
180 add_stat(stats,
"enterprise",
false);
181 add_stat(stats,
"clientType", protocol::ClientTypes::CPP);
182 add_stat(stats,
"clientVersion", HAZELCAST_VERSION);
184 "clusterConnectionTimestamp",
185 std::chrono::duration_cast<std::chrono::milliseconds>(
186 connection->get_start_time().time_since_epoch())
189 auto localSocketAddress = connection->get_local_socket_address();
190 stats << STAT_SEPARATOR <<
"clientAddress" << KEY_VALUE_SEPARATOR;
191 if (localSocketAddress) {
192 stats << localSocketAddress->get_host() <<
":"
193 << localSocketAddress->get_port();
196 add_stat(stats,
"clientName", statistics_.client_context_.get_name());
199 statistics_.client_context_.get_client_config().get_credentials();
201 add_stat(stats,
"credentials.principal", credential->name());
204 auto hw_concurrency = std::thread::hardware_concurrency();
206 add_stat(stats,
"runtime.availableProcessors", hw_concurrency);
208 {
"runtime",
"availableProcessors", metrics::probe_unit::COUNT },
215 Statistics::PeriodicStatistics::add_near_cache_stats(
216 std::ostringstream& stats,
217 metrics::metrics_compressor& compressor)
219 for (
auto near_cache : statistics_.client_context_.get_near_cache_manager()
220 .list_all_near_caches()) {
221 std::string nc_name = near_cache->get_name();
223 std::ostringstream nc_name_with_prefix_strm;
224 get_name_with_prefix(nc_name, nc_name_with_prefix_strm);
225 nc_name_with_prefix_strm <<
'.';
226 std::string nc_name_with_prefix = nc_name_with_prefix_strm.str();
229 std::static_pointer_cast<monitor::impl::NearCacheStatsImpl>(
230 near_cache->get_near_cache_stats());
232 add_near_cache_metric(stats,
237 nc_stats->get_creation_time(),
238 metrics::probe_unit::MS);
240 add_near_cache_metric(stats,
245 nc_stats->get_evictions(),
246 metrics::probe_unit::COUNT);
248 add_near_cache_metric(stats,
253 nc_stats->get_hits(),
254 metrics::probe_unit::COUNT);
256 add_near_cache_metric(stats,
258 "lastPersistenceDuration",
261 nc_stats->get_last_persistence_duration(),
262 metrics::probe_unit::MS);
264 add_near_cache_metric(stats,
266 "lastPersistenceKeyCount",
269 nc_stats->get_last_persistence_key_count(),
270 metrics::probe_unit::COUNT);
272 add_near_cache_metric(stats,
274 "lastPersistenceTime",
277 nc_stats->get_last_persistence_time(),
278 metrics::probe_unit::MS);
280 add_near_cache_metric(stats,
282 "lastPersistenceWrittenBytes",
285 nc_stats->get_last_persistence_written_bytes(),
286 metrics::probe_unit::BYTES);
288 add_near_cache_metric(stats,
293 nc_stats->get_misses(),
294 metrics::probe_unit::COUNT);
296 add_near_cache_metric(stats,
301 nc_stats->get_owned_entry_count(),
302 metrics::probe_unit::COUNT);
304 add_near_cache_metric(stats,
309 nc_stats->get_expirations(),
310 metrics::probe_unit::COUNT);
312 add_near_cache_metric(stats,
317 nc_stats->get_invalidations(),
318 metrics::probe_unit::COUNT);
320 add_near_cache_metric(stats,
322 "invalidationRequests",
325 nc_stats->get_invalidation_requests(),
326 metrics::probe_unit::COUNT);
328 add_near_cache_metric(stats,
330 "ownedEntryMemoryCost",
333 nc_stats->get_owned_entry_memory_cost(),
334 metrics::probe_unit::BYTES);
339 Statistics::PeriodicStatistics::add_near_cache_metric(
340 std::ostringstream& stats,
341 metrics::metrics_compressor& compressor,
342 const std::string& metric,
343 const std::string& near_cache_name,
344 const std::string& near_cache_name_with_prefix,
346 metrics::probe_unit unit)
349 metrics::metric_descriptor desc{
350 "nearcache", metric,
"name", near_cache_name, unit
352 compressor.add_long(desc, value);
355 add_stat(stats, near_cache_name_with_prefix, metric, value);
358 Statistics::PeriodicStatistics::PeriodicStatistics(Statistics& statistics)
359 : statistics_(statistics)
363 Statistics::escape_special_characters(std::string& name)
365 boost::replace_all(name,
",",
"\\,");
366 boost::replace_all(name,
"=",
"\\=");
367 boost::replace_all(name,
"\\",
"\\\\");
369 return name[0] ==
'/' ? name.substr(1) : name;
373 Statistics::PeriodicStatistics::get_name_with_prefix(std::string& name,
374 std::ostringstream& out)
376 out << NEAR_CACHE_CATEGORY_PREFIX
377 << Statistics::escape_special_characters(name);
382 Statistics::PeriodicStatistics::add_stat(std::ostringstream& stats,
383 const std::string& name,
386 stats << STAT_SEPARATOR << name << KEY_VALUE_SEPARATOR
387 << (value ?
"true" :
"false");
394 const int64_t local_instance_stats::STAT_NOT_AVAILABLE = -99L;
397 LocalMapStatsImpl::LocalMapStatsImpl() =
default;
399 LocalMapStatsImpl::LocalMapStatsImpl(
400 const std::shared_ptr<monitor::near_cache_stats>& s)
401 : near_cache_stats_(s)
404 std::shared_ptr<monitor::near_cache_stats>
405 LocalMapStatsImpl::get_near_cache_stats()
const
407 return near_cache_stats_;
410 NearCacheStatsImpl::NearCacheStatsImpl()
411 : creation_time_(util::current_time_millis())
412 , owned_entry_count_(0)
413 , owned_entry_memory_cost_(0)
419 , invalidation_requests_(0)
420 , persistence_count_(0)
421 , last_persistence_time_(0)
422 , last_persistence_duration_(0)
423 , last_persistence_written_bytes_(0)
424 , last_persistence_key_count_(0)
425 , last_persistence_failure_(
"")
429 NearCacheStatsImpl::get_creation_time()
431 return creation_time_;
435 NearCacheStatsImpl::get_owned_entry_count()
437 return owned_entry_count_;
441 NearCacheStatsImpl::set_owned_entry_count(int64_t owned_entry_count)
443 this->owned_entry_count_ = owned_entry_count;
447 NearCacheStatsImpl::increment_owned_entry_count()
449 ++owned_entry_count_;
453 NearCacheStatsImpl::decrement_owned_entry_count()
455 --owned_entry_count_;
459 NearCacheStatsImpl::get_owned_entry_memory_cost()
461 return owned_entry_memory_cost_;
465 NearCacheStatsImpl::set_owned_entry_memory_cost(int64_t owned_entry_memory_cost)
467 this->owned_entry_memory_cost_ = owned_entry_memory_cost;
471 NearCacheStatsImpl::increment_owned_entry_memory_cost(
472 int64_t owned_entry_memory_cost)
474 this->owned_entry_memory_cost_ += owned_entry_memory_cost;
478 NearCacheStatsImpl::decrement_owned_entry_memory_cost(
479 int64_t owned_entry_memory_cost)
481 this->owned_entry_memory_cost_ -= owned_entry_memory_cost;
485 NearCacheStatsImpl::get_hits()
492 NearCacheStatsImpl::set_hits(int64_t hits)
498 NearCacheStatsImpl::increment_hits()
504 NearCacheStatsImpl::get_misses()
511 NearCacheStatsImpl::set_misses(int64_t misses)
513 this->misses_ = misses;
517 NearCacheStatsImpl::increment_misses()
523 NearCacheStatsImpl::get_ratio()
525 if (misses_ == (int64_t)0) {
526 if (hits_ == (int64_t)0) {
527 return std::numeric_limits<double>::signaling_NaN();
529 return std::numeric_limits<double>::infinity();
532 return ((
double)hits_ / misses_) * PERCENTAGE;
537 NearCacheStatsImpl::get_evictions()
543 NearCacheStatsImpl::increment_evictions()
549 NearCacheStatsImpl::get_expirations()
555 NearCacheStatsImpl::increment_expirations()
561 NearCacheStatsImpl::get_invalidations()
563 return invalidations_.load();
567 NearCacheStatsImpl::increment_invalidations()
573 NearCacheStatsImpl::get_invalidation_requests()
575 return invalidation_requests_.load();
579 NearCacheStatsImpl::increment_invalidation_requests()
581 ++invalidation_requests_;
585 NearCacheStatsImpl::reset_invalidation_events()
587 invalidation_requests_ = 0;
591 NearCacheStatsImpl::get_persistence_count()
593 return persistence_count_;
597 NearCacheStatsImpl::add_persistence(int64_t duration,
598 int32_t written_bytes,
601 ++persistence_count_;
602 last_persistence_time_ = util::current_time_millis();
603 last_persistence_duration_ = duration;
604 last_persistence_written_bytes_ = written_bytes;
605 last_persistence_key_count_ = key_count;
606 last_persistence_failure_ =
"";
610 NearCacheStatsImpl::get_last_persistence_time()
612 return last_persistence_time_;
616 NearCacheStatsImpl::get_last_persistence_duration()
618 return last_persistence_duration_;
622 NearCacheStatsImpl::get_last_persistence_written_bytes()
624 return last_persistence_written_bytes_;
628 NearCacheStatsImpl::get_last_persistence_key_count()
630 return last_persistence_key_count_;
634 NearCacheStatsImpl::get_last_persistence_failure()
636 return last_persistence_failure_;
640 NearCacheStatsImpl::to_string()
642 std::ostringstream out;
643 std::string failureString = last_persistence_failure_;
644 out <<
"NearCacheStatsImpl{"
645 <<
"ownedEntryCount=" << owned_entry_count_
646 <<
", ownedEntryMemoryCost=" << owned_entry_memory_cost_
647 <<
", creationTime=" << creation_time_ <<
", hits=" << hits_
648 <<
", misses=" << misses_ <<
", ratio=" << std::setprecision(1)
649 << get_ratio() <<
", evictions=" << evictions_
650 <<
", expirations=" << expirations_
651 <<
", invalidations=" << invalidations_.load()
652 <<
", invalidationRequests=" << invalidation_requests_.load()
653 <<
", lastPersistenceTime=" << last_persistence_time_
654 <<
", persistenceCount=" << persistence_count_
655 <<
", lastPersistenceDuration=" << last_persistence_duration_
656 <<
", lastPersistenceWrittenBytes=" << last_persistence_written_bytes_
657 <<
", lastPersistenceKeyCount=" << last_persistence_key_count_
658 <<
", lastPersistenceFailure='" << failureString <<
"'" <<
'}';
663 const double NearCacheStatsImpl::PERCENTAGE = 100.0;