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 ();
@@ -112,7 +120,6 @@ absl::Status LogsHandler::changeLogLevel(Http::Utility::QueryParamsMulti& params
112120 }
113121
114122 Logger::Context::changeAllLogLevels (*level_to_use);
115- return absl::OkStatus ();
116123 }
117124
118125 // Build a map of name:level pairs, a few allocations is ok here since it's
@@ -128,12 +135,12 @@ absl::Status LogsHandler::changeLogLevel(Http::Utility::QueryParamsMulti& params
128135 for (const auto & name_level : pairs) {
129136 const std::pair<absl::string_view, absl::string_view> name_level_pair =
130137 absl::StrSplit (name_level, absl::MaxSplits (' :' , 1 ), absl::SkipWhitespace ());
131- auto [name, level ] = name_level_pair;
132- if (name.empty () || level .empty ()) {
138+ auto [name, level_str ] = name_level_pair;
139+ if (name.empty () || level_str .empty ()) {
133140 return absl::InvalidArgumentError (" empty logger name or empty logger level" );
134141 }
135142
136- const absl::StatusOr<spdlog::level::level_enum> level_to_use = parseLogLevel (level );
143+ const absl::StatusOr<spdlog::level::level_enum> level_to_use = parseLogLevel (level_str );
137144 if (!level_to_use.ok ()) {
138145 return level_to_use.status ();
139146 }
@@ -146,6 +153,29 @@ absl::Status LogsHandler::changeLogLevel(Http::Utility::QueryParamsMulti& params
146153 name_levels[name] = *level_to_use;
147154 }
148155 }
156+ } else if (group.has_value ()) {
157+ // Group parameter requires fine-grain logging to be enabled
158+ if (!use_fine_grain_logger) {
159+ return absl::InvalidArgumentError (
160+ " group parameter requires fine-grain logging to be enabled" );
161+ }
162+ const std::pair<absl::string_view, absl::string_view> name_level_pair =
163+ absl::StrSplit (group.value (), absl::MaxSplits (' :' , 1 ), absl::SkipWhitespace ());
164+ auto [name, level_str] = name_level_pair;
165+ if (name.empty () || level_str.empty ()) {
166+ return absl::InvalidArgumentError (" empty logger name or empty logger level in group" );
167+ }
168+ const absl::StatusOr<spdlog::level::level_enum> level_to_use = parseLogLevel (level_str);
169+ if (!level_to_use.ok ()) {
170+ return level_to_use.status ();
171+ }
172+ if (Logger::Registry::logger (std::string (name)) != nullptr ) {
173+ ENVOY_LOG (info, " adding fine-grain log update, glob='{}' level='{}'" , name,
174+ spdlog::level::level_string_views[*level_to_use]);
175+ glob_levels.emplace_back (name, *level_to_use);
176+ } else {
177+ return absl::InvalidArgumentError (fmt::format (" unknown logger group: {}" , name));
178+ }
149179 } else {
150180 // The HTML admin interface will always populate "level" and "paths" though
151181 // they may be empty. There's a legacy non-HTML-accessible mechanism to
0 commit comments