11#include " source/server/admin/logs_handler.h"
22
33#include < string>
4+ #include < vector>
45
56#include " source/common/common/fine_grain_logger.h"
67#include " source/common/common/logger.h"
78#include " source/server/admin/utils.h"
89
910#include " absl/strings/str_split.h"
11+ #include " fmt/format.h"
1012
1113namespace Envoy {
1214namespace Server {
@@ -50,6 +52,7 @@ Http::Code LogsHandler::handlerLogging(Http::ResponseHeaderMap&, Buffer::Instanc
5052 response.add (" usage: /logging?<name>=<level> (change single level)\n " );
5153 response.add (" usage: /logging?paths=name1:level1,name2:level2,... (change multiple levels)\n " );
5254 response.add (" usage: /logging?level=<level> (change all levels)\n " );
55+ response.add (" usage: /logging?group=<group_name>:<level> (change group of loggers)\n " );
5356 response.add (" levels: " );
5457 for (auto level_string_view : spdlog::level::level_string_views) {
5558 response.add (fmt::format (" {} " , level_string_view));
@@ -83,7 +86,7 @@ Http::Code LogsHandler::handlerReopenLogs(Http::ResponseHeaderMap&, Buffer::Inst
8386}
8487
8588absl::Status LogsHandler::changeLogLevel (Http::Utility::QueryParamsMulti& params) {
86- // "level" and "paths " will be set to the empty string when this is invoked
89+ // "level", "paths", and "group " will be set to the empty string when this is invoked
8790 // from HTML without setting them, so clean out empty values.
8891 auto level = params.getFirstValue (" level" );
8992 if (level.has_value () && level.value ().empty ()) {
@@ -95,6 +98,11 @@ absl::Status LogsHandler::changeLogLevel(Http::Utility::QueryParamsMulti& params
9598 params.remove (" paths" );
9699 paths = std::nullopt ;
97100 }
101+ auto group = params.getFirstValue (" group" );
102+ if (group.has_value () && group.value ().empty ()) {
103+ params.remove (" group" );
104+ group = std::nullopt ;
105+ }
98106
99107 if (params.data ().empty ()) {
100108 return absl::OkStatus ();
@@ -128,12 +136,12 @@ absl::Status LogsHandler::changeLogLevel(Http::Utility::QueryParamsMulti& params
128136 for (const auto & name_level : pairs) {
129137 const std::pair<absl::string_view, absl::string_view> name_level_pair =
130138 absl::StrSplit (name_level, absl::MaxSplits (' :' , 1 ), absl::SkipWhitespace ());
131- auto [name, level ] = name_level_pair;
132- if (name.empty () || level .empty ()) {
139+ auto [name, level_str ] = name_level_pair;
140+ if (name.empty () || level_str .empty ()) {
133141 return absl::InvalidArgumentError (" empty logger name or empty logger level" );
134142 }
135143
136- const absl::StatusOr<spdlog::level::level_enum> level_to_use = parseLogLevel (level );
144+ const absl::StatusOr<spdlog::level::level_enum> level_to_use = parseLogLevel (level_str );
137145 if (!level_to_use.ok ()) {
138146 return level_to_use.status ();
139147 }
@@ -146,6 +154,29 @@ absl::Status LogsHandler::changeLogLevel(Http::Utility::QueryParamsMulti& params
146154 name_levels[name] = *level_to_use;
147155 }
148156 }
157+ } else if (group.has_value ()) {
158+ // Group parameter requires fine-grain logging to be enabled
159+ if (!use_fine_grain_logger) {
160+ return absl::InvalidArgumentError (
161+ " group parameter requires fine-grain logging to be enabled" );
162+ }
163+ const std::pair<absl::string_view, absl::string_view> name_level_pair =
164+ absl::StrSplit (group.value (), absl::MaxSplits (' :' , 1 ), absl::SkipWhitespace ());
165+ auto [name, level_str] = name_level_pair;
166+ if (name.empty () || level_str.empty ()) {
167+ return absl::InvalidArgumentError (" empty logger name or empty logger level in group" );
168+ }
169+ const absl::StatusOr<spdlog::level::level_enum> level_to_use = parseLogLevel (level_str);
170+ if (!level_to_use.ok ()) {
171+ return level_to_use.status ();
172+ }
173+ if (Logger::Registry::logger (std::string (name)) != nullptr ) {
174+ ENVOY_LOG (info, " adding fine-grain log update, glob='{}' level='{}'" , name,
175+ spdlog::level::level_string_views[*level_to_use]);
176+ glob_levels.emplace_back (name, *level_to_use);
177+ } else {
178+ return absl::InvalidArgumentError (fmt::format (" unknown logger group: {}" , name));
179+ }
149180 } else {
150181 // The HTML admin interface will always populate "level" and "paths" though
151182 // they may be empty. There's a legacy non-HTML-accessible mechanism to
0 commit comments