@@ -3270,7 +3270,7 @@ string ServerFamily::FormatInfoMetrics(const Metrics& m, std::string_view sectio
32703270 if (show) {
32713271 size_t total = stats.events .hits + stats.events .misses ;
32723272 double hit_ratio =
3273- (total > 0 ) ? static_cast <double >(stats.events .hits ) / (total)* 100.0 : 0.0 ;
3273+ (total > 0 ) ? static_cast <double >(stats.events .hits ) / (total) * 100.0 : 0.0 ;
32743274 string val = StrCat (" keys=" , stats.key_count , " ,expires=" , stats.expire_count ,
32753275 " ,hits=" , stats.events .hits , " ,misses=" , stats.events .misses ,
32763276 " ,hit_ratio=" , absl::StrFormat (" %.2f" , hit_ratio),
@@ -3330,26 +3330,44 @@ string ServerFamily::FormatInfoMetrics(const Metrics& m, std::string_view sectio
33303330}
33313331
33323332void ServerFamily::Info (CmdArgList args, const CommandContext& cmd_cntx) {
3333- if (args.size () > 1 ) {
3334- return cmd_cntx.rb ->SendError (kSyntaxErr );
3335- }
3336-
3337- string section;
3333+ std::vector<std::string> sections;
3334+ auto need_metrics{false }; // Save time - do not fetch metrics if we don't need them.
3335+ Metrics metrics;
33383336
3339- if (args.size () == 1 ) {
3340- section = absl::AsciiStrToUpper (ArgS (args, 0 ));
3337+ sections.reserve (args.size ());
3338+ for (const auto & arg : args) {
3339+ sections.emplace_back (absl::AsciiStrToUpper (arg));
3340+ const auto & section = sections.back ();
3341+ if (!need_metrics && (section != " SERVER" ) && (section != " REPLICATION" )) {
3342+ need_metrics = true ;
3343+ metrics = GetMetrics (cmd_cntx.conn_cntx ->ns );
3344+ }
33413345 }
33423346
3343- Metrics metrics;
3344-
3345- // Save time by not calculating metrics if we don't need them.
3346- if (!(section == " SERVER" || section == " REPLICATION" )) {
3347- metrics = GetMetrics (cmd_cntx.conn_cntx ->ns );
3348- } else if (!IsMaster ()) {
3347+ if (!need_metrics && !IsMaster ()) {
33493348 metrics.replica_side_info = GetReplicaSummary ();
33503349 }
33513350
3352- string info = FormatInfoMetrics (metrics, section, cmd_cntx.conn_cntx ->conn ()->IsPrivileged ());
3351+ std::string info;
3352+ // For multiple requested sections, invalid section names are ignored (not included in the output).
3353+ // The command does not abort or return an error if some sections are invalid. This matches Redis behavior.
3354+ if (sections.empty ()) { // No sections: default to all sections.
3355+ info = FormatInfoMetrics (metrics, " " , cmd_cntx.conn_cntx ->conn ()->IsPrivileged ());
3356+ } else if (sections.size () == 1 ) { // Single section
3357+ info = FormatInfoMetrics (metrics, sections[0 ], cmd_cntx.conn_cntx ->conn ()->IsPrivileged ());
3358+ } else { // Multiple sections: concatenate results for each requested section.
3359+ for (const auto & section : sections) {
3360+ const std::string section_str =
3361+ FormatInfoMetrics (metrics, section, cmd_cntx.conn_cntx ->conn ()->IsPrivileged ());
3362+ if (!section_str.empty ()) {
3363+ if (!info.empty ()) {
3364+ absl::StrAppend (&info, " \r\n " , section_str);
3365+ } else {
3366+ info = section_str;
3367+ }
3368+ }
3369+ }
3370+ }
33533371
33543372 auto * rb = static_cast <RedisReplyBuilder*>(cmd_cntx.rb );
33553373 rb->SendVerbatimString (info);
0 commit comments