| 485 | } |
| 486 | |
| 487 | void handle_client_list_response(struct RedisModuleCtx *ctx, const char *szReply, size_t len) { |
| 488 | size_t totalClientOutputBuffer = 0; |
| 489 | size_t totalReplicaClientOutputBuffer = 0; |
| 490 | #define SAFETY_CHECK_POINTER(_p) ((_p) < (szReply + len)) |
| 491 | const char *pchLineStart = szReply; |
| 492 | while (SAFETY_CHECK_POINTER(pchLineStart) && *pchLineStart != '\0') { |
| 493 | // Loop Each Line |
| 494 | const char *pchLineEnd = pchLineStart; |
| 495 | while (SAFETY_CHECK_POINTER(pchLineEnd) && (*pchLineEnd != '\r') && (*pchLineEnd != '\n')) { |
| 496 | ++pchLineEnd; |
| 497 | } |
| 498 | std::string line(pchLineStart, pchLineEnd - pchLineStart); |
| 499 | RedisModule_Log(ctx, REDISMODULE_LOGLEVEL_DEBUG, "Client List Line: \"%s\"", line.c_str()); |
| 500 | |
| 501 | // recover output buffer size for client |
| 502 | bool lineFailed = false; |
| 503 | bool replica = line.find("flags=S") != std::string::npos; |
| 504 | size_t idx = line.find("omem"); |
| 505 | if (!(lineFailed = (idx == std::string::npos))) { |
| 506 | std::string rest = line.substr(idx); |
| 507 | size_t startIdx = rest.find("="); |
| 508 | if (!(lineFailed = (startIdx == std::string::npos))) { |
| 509 | size_t endIdx = rest.find(" "); |
| 510 | if (!(lineFailed = (endIdx == std::string::npos))) { |
| 511 | // use startIdx + 1 and endIdx - 1 to exclude the '=' and ' ' characters |
| 512 | std::string valueString = rest.substr(startIdx + 1, (endIdx - 1) - (startIdx + 1)); |
| 513 | size_t value = strtoll(valueString.c_str(), nullptr, 10); |
| 514 | totalClientOutputBuffer += value; |
| 515 | if (replica) { |
| 516 | totalReplicaClientOutputBuffer += value; |
| 517 | } |
| 518 | } |
| 519 | } |
| 520 | } |
| 521 | |
| 522 | if (lineFailed) { |
| 523 | RedisModule_Log(ctx, REDISMODULE_LOGLEVEL_WARNING, "Unexpected CLIENT format returned by \"CLIENT LIST\" command: \"%s\"", line.c_str()); |
| 524 | } |
| 525 | |
| 526 | pchLineStart = pchLineEnd; |
| 527 | while (SAFETY_CHECK_POINTER(pchLineStart) && ((*pchLineStart == '\r') || (*pchLineStart == '\n'))) { |
| 528 | ++pchLineStart; |
| 529 | } |
| 530 | } |
| 531 | #undef SAFETY_CHECK_POINTER |
| 532 | g_stats->gauge("total_client_output_buffer", totalClientOutputBuffer); |
| 533 | g_stats->gauge("total_replica_client_output_buffer", totalReplicaClientOutputBuffer); |
| 534 | } |
| 535 | |
| 536 | void emit_system_free_memory() { |
| 537 | std::ifstream meminfo("/proc/meminfo"); |