Skip to content

Commit 7d4987a

Browse files
committed
Implement fine grain logging groups
Signed-off-by: Ethan Truong <ethantruong@google.com>
1 parent e0c05d5 commit 7d4987a

14 files changed

Lines changed: 274 additions & 82 deletions

File tree

source/common/common/fine_grain_logger.cc

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "source/common/common/fine_grain_logger.h"
22

33
#include <atomic>
4+
#include <cstddef>
45
#include <memory>
56
#include <tuple>
67

@@ -209,11 +210,19 @@ void FineGrainLogContext::appendVerbosityLogUpdate(absl::string_view update_patt
209210
verbosity_update_info_.emplace_back(std::string(update_pattern), update_is_path, log_level);
210211
}
211212

212-
level_enum FineGrainLogContext::getLogLevel(absl::string_view file) const {
213+
level_enum FineGrainLogContext::getLogLevel(absl::string_view key) const {
213214
if (verbosity_update_info_.empty()) {
214215
return verbosity_default_level_;
215216
}
216217

218+
absl::string_view file = key;
219+
absl::string_view logger_name;
220+
const size_t colon = file.rfind(':');
221+
if (colon != file.npos) {
222+
logger_name = file.substr(colon + 1);
223+
file = file.substr(0, colon);
224+
}
225+
217226
// Get basename for file.
218227
absl::string_view basename = file;
219228
{
@@ -236,8 +245,13 @@ level_enum FineGrainLogContext::getLogLevel(absl::string_view file) const {
236245
if (safeFileNameMatch(info.update_pattern, file)) {
237246
return info.log_level;
238247
}
239-
} else if (safeFileNameMatch(info.update_pattern, stem_basename)) {
240-
return info.log_level;
248+
} else {
249+
if (safeFileNameMatch(info.update_pattern, stem_basename)) {
250+
return info.log_level;
251+
}
252+
if (!logger_name.empty() && safeFileNameMatch(info.update_pattern, logger_name)) {
253+
return info.log_level;
254+
}
241255
}
242256
}
243257

source/common/common/fine_grain_logger.h

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,10 @@ class FineGrainLogContext {
154154
ABSL_EXCLUSIVE_LOCKS_REQUIRED(fine_grain_log_lock_);
155155

156156
/**
157-
* Returns the current log level of `file`. Default log level is used if there is no
157+
* Returns the current log level of `key`. Default log level is used if there is no
158158
* match in verbosity_update_info_.
159159
*/
160-
spdlog::level::level_enum getLogLevel(absl::string_view file) const
160+
spdlog::level::level_enum getLogLevel(absl::string_view key) const
161161
ABSL_SHARED_LOCKS_REQUIRED(fine_grain_log_lock_);
162162

163163
/**
@@ -194,12 +194,17 @@ FineGrainLogContext& getFineGrainLogContext();
194194
* The local pointer is used to avoid another load() when logging. Here we use
195195
* spdlog::logger* as atomic<shared_ptr> is a C++20 feature.
196196
*/
197-
#define FINE_GRAIN_LOGGER() \
198-
([]() -> spdlog::logger* { \
197+
#define FINE_GRAIN_LOGGER(NAME) \
198+
([&]() -> spdlog::logger* { \
199199
static std::atomic<spdlog::logger*> flogger{nullptr}; \
200200
spdlog::logger* local_flogger = flogger.load(std::memory_order_acquire); \
201201
if (!local_flogger) { \
202-
::Envoy::getFineGrainLogContext().initFineGrainLogger(__FILE__, flogger); \
202+
const std::string logger_name(NAME); \
203+
std::string key = __FILE__; \
204+
if (!logger_name.empty()) { \
205+
key = key + ":" + logger_name; \
206+
} \
207+
::Envoy::getFineGrainLogContext().initFineGrainLogger(key, flogger); \
203208
local_flogger = flogger.load(std::memory_order_acquire); \
204209
} \
205210
return local_flogger; \
@@ -208,9 +213,9 @@ FineGrainLogContext& getFineGrainLogContext();
208213
/**
209214
* Macro for fine-grain logger to log.
210215
*/
211-
#define FINE_GRAIN_LOG(LEVEL, ...) \
216+
#define FINE_GRAIN_LOG(LEVEL, NAME, ...) \
212217
do { \
213-
spdlog::logger* local_flogger = FINE_GRAIN_LOGGER(); \
218+
spdlog::logger* local_flogger = FINE_GRAIN_LOGGER(NAME); \
214219
if (ENVOY_LOG_COMP_LEVEL(*local_flogger, LEVEL)) { \
215220
local_flogger->log(spdlog::source_loc{__FILE__, __LINE__, __func__}, \
216221
ENVOY_SPDLOG_LEVEL(LEVEL), __VA_ARGS__); \
@@ -221,22 +226,27 @@ FineGrainLogContext& getFineGrainLogContext();
221226
* Convenient macro for connection log.
222227
*/
223228
#define FINE_GRAIN_CONN_LOG(LEVEL, FORMAT, CONNECTION, ...) \
224-
FINE_GRAIN_LOG(LEVEL, "[C{}] " FORMAT, (CONNECTION).id(), ##__VA_ARGS__)
229+
FINE_GRAIN_LOG(LEVEL, "", "[C{}] " FORMAT, (CONNECTION).id(), ##__VA_ARGS__)
225230

226231
/**
227232
* Convenient macro for stream log.
228233
*/
229234
#define FINE_GRAIN_STREAM_LOG(LEVEL, FORMAT, STREAM, ...) \
230-
FINE_GRAIN_LOG(LEVEL, "[C{}][S{}] " FORMAT, \
235+
FINE_GRAIN_LOG(LEVEL, "", "[C{}][S{}] " FORMAT, \
231236
(STREAM).connection() ? (STREAM).connection()->id() : 0, (STREAM).streamId(), \
232237
##__VA_ARGS__)
233238

234239
/**
235240
* Convenient macro for log flush.
236241
*/
237-
#define FINE_GRAIN_FLUSH_LOG() \
242+
#define FINE_GRAIN_FLUSH_LOG(NAME) \
238243
do { \
239-
SpdLoggerSharedPtr p = ::Envoy::getFineGrainLogContext().getFineGrainLogEntry(__FILE__); \
244+
const std::string logger_name(NAME); \
245+
std::string key = __FILE__; \
246+
if (!logger_name.empty()) { \
247+
key = key + ":" + logger_name; \
248+
} \
249+
SpdLoggerSharedPtr p = ::Envoy::getFineGrainLogContext().getFineGrainLogEntry(key); \
240250
if (p) { \
241251
p->flush(); \
242252
} \

source/common/common/logger.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ void Context::changeAllLogLevels(spdlog::level::level_enum level) {
174174
} else {
175175
// Level setting with Fine-Grain Logger.
176176
FINE_GRAIN_LOG(
177-
info,
177+
info, "",
178178
"change all log levels and default verbosity level for fine grain loggers: level='{}'",
179179
spdlog::level::level_string_views[level]);
180180
getFineGrainLogContext().updateVerbosityDefaultLevel(level);

source/common/common/logger.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ class ExtractedMessage : public spdlog::custom_flag_formatter {
498498
*/
499499
#define ENVOY_LOG_COMP_LEVEL_FINE_GRAIN_IF(LOGGER, LEVEL) \
500500
(Envoy::Logger::Context::useFineGrainLogger() \
501-
? (ENVOY_SPDLOG_LEVEL(LEVEL) >= (*FINE_GRAIN_LOGGER()).level()) \
501+
? (ENVOY_SPDLOG_LEVEL(LEVEL) >= (*FINE_GRAIN_LOGGER(LOGGER.name())).level()) \
502502
: (ENVOY_SPDLOG_LEVEL(LEVEL) >= (LOGGER).level()))
503503

504504
/**
@@ -523,7 +523,7 @@ class ExtractedMessage : public spdlog::custom_flag_formatter {
523523
#define ENVOY_LOG_TO_LOGGER(LOGGER, LEVEL, ...) \
524524
do { \
525525
if (Envoy::Logger::should_log && Envoy::Logger::Context::useFineGrainLogger()) { \
526-
FINE_GRAIN_LOG(LEVEL, ##__VA_ARGS__); \
526+
FINE_GRAIN_LOG(LEVEL, LOGGER.name(), ##__VA_ARGS__); \
527527
} else { \
528528
ENVOY_LOG_COMP_AND_LOG(LOGGER, LEVEL, ##__VA_ARGS__); \
529529
} \
@@ -775,7 +775,7 @@ using t_logclock = std::chrono::steady_clock; // NOLINT
775775
#define ENVOY_FLUSH_LOG() \
776776
do { \
777777
if (Envoy::Logger::Context::useFineGrainLogger()) { \
778-
FINE_GRAIN_FLUSH_LOG(); \
778+
FINE_GRAIN_FLUSH_LOG(ENVOY_LOGGER().name()); \
779779
} else { \
780780
ENVOY_LOGGER().flush(); \
781781
} \

source/docs/fine_grain_log.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ Fine-Grain Logger is a logger with finer grained log level control and runtime l
77
### Basic Usage
88
The basic usage of Fine-Grain Logger is to explicitly call its macros:
99
```
10-
FINE_GRAIN_LOG(info, "Hello world! Here's a line of fine-grain log!");
11-
FINE_GRAIN_LOG(error, "FineGrainLog Error! Here's the second message!");
10+
FINE_GRAIN_LOG(info, "", "Hello world! Here's a line of fine-grain log!");
11+
FINE_GRAIN_LOG(error, "", "FineGrainLog Error! Here's the second message!");
1212
```
1313
If the level of log message is higher than that of the file, macros above will print messages with the file name like this:
1414
```

source/extensions/load_balancing_policies/common/thread_aware_lb_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class ThreadAwareLoadBalancerBase : public LoadBalancerBase, public ThreadAwareL
4242
host->metadata().get(), Config::MetadataFilters::get().ENVOY_LB,
4343
Config::MetadataEnvoyLbKeys::get().HASH_KEY);
4444
if (val.kind_case() != val.kStringValue && val.kind_case() != val.KIND_NOT_SET) {
45-
FINE_GRAIN_LOG(debug, "hash_key must be string type, got: {}",
45+
FINE_GRAIN_LOG(debug, "", "hash_key must be string type, got: {}",
4646
static_cast<int>(val.kind_case()));
4747
}
4848
absl::string_view hash_key = val.string_value();

source/server/admin/admin.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,10 @@ AdminImpl::AdminImpl(const std::string& profile_path, Server::Instance& server,
198198
"If fine grain logging is enabled, use __FILE__ or a glob experision as "
199199
"the logger name. "
200200
"For example, source/common*:warning"},
201+
{Admin::ParamDescriptor::Type::String, "group",
202+
"Change given logger group to desired level, set to "
203+
"<logger_group_name>:<desired_level>. "
204+
"logger_group_name can be a logger name or a glob expression."},
201205
{Admin::ParamDescriptor::Type::Enum, "level",
202206
"desired logging level, this will change all loggers's level",
203207
prepend("", LogsHandler::levelStrings())}}),

source/server/admin/logs_handler.cc

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
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

1113
namespace Envoy {
1214
namespace 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

8588
absl::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

source/server/admin/logs_handler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "envoy/server/admin.h"
77
#include "envoy/server/instance.h"
88

9+
#include "source/common/common/logger.h"
910
#include "source/server/admin/handler_ctx.h"
1011

1112
#include "absl/container/flat_hash_map.h"

0 commit comments

Comments
 (0)