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;