Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

*: Combine LOG_XXX and LOG_FMT_XXX #5512

Merged
merged 8 commits into from
Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
45 changes: 45 additions & 0 deletions libs/libcommon/include/common/MacroUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2022 PingCAP, Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#define TF_GET_1ST_ARG(a, ...) a
#define TF_GET_2ND_ARG(a1, a2, ...) a2
#define TF_GET_3RD_ARG(a1, a2, a3, ...) a3
#define TF_GET_4TH_ARG(a1, a2, a3, a4, ...) a4
#define TF_GET_5TH_ARG(a1, a2, a3, a4, a5, ...) a5
#define TF_GET_6TH_ARG(a1, a2, a3, a4, a5, a6, ...) a6
#define TF_GET_7TH_ARG(a1, a2, a3, a4, a5, a6, a7, ...) a7
#define TF_GET_8TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, ...) a8
#define TF_GET_9TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, ...) a9
#define TF_GET_10TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, ...) a10
#define TF_GET_11TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, ...) a11
#define TF_GET_12TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, ...) a12
#define TF_GET_13TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, ...) a13
#define TF_GET_14TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, ...) a14
#define TF_GET_15TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, ...) a15
#define TF_GET_16TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, ...) a16
#define TF_GET_17TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, ...) a17
#define TF_GET_18TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, ...) a18
#define TF_GET_19TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, ...) a19
#define TF_GET_20TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, ...) a20
#define TF_GET_21TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, ...) a21
#define TF_GET_22TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, ...) a22
#define TF_GET_23TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, ...) a23
#define TF_GET_24TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, ...) a24
#define TF_GET_25TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, ...) a25
#define TF_GET_26TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, ...) a26
#define TF_GET_27TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, ...) a27
#define TF_GET_28TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, ...) a28
#define TF_GET_29TH_ARG(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, ...) a29
113 changes: 50 additions & 63 deletions libs/libcommon/include/common/logger_useful.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
/// Macros for convenient usage of Poco logger.

#include <Poco/Logger.h>
#include <common/MacroUtils.h>
#include <fmt/format.h>
#include <fmt/ranges.h>

Expand All @@ -26,17 +27,6 @@

namespace LogFmtDetails
{
template <typename... Ts>
inline constexpr size_t numArgs(Ts &&...)
{
return sizeof...(Ts);
}
template <typename T, typename... Ts>
inline constexpr auto firstArg(T && x, Ts &&...)
{
return std::forward<T>(x);
}

// https://stackoverflow.com/questions/8487986/file-macro-shows-full-path/54335644#54335644
template <typename T, size_t S>
inline constexpr size_t getFileNameOffset(const T (&str)[S], size_t i = S - 1)
Expand All @@ -50,8 +40,8 @@ inline constexpr size_t getFileNameOffset(T (&/*str*/)[1])
return 0;
}

template <typename S, typename Ignored, typename... Args>
std::string toCheckedFmtStr(const S & format, const Ignored &, Args &&... args)
template <typename S, typename... Args>
std::string toCheckedFmtStr(const S & format, Args &&... args)
{
// The second arg is the same as `format`, just ignore
// Apply `make_args_checked` for checks `format` validity at compile time.
Expand All @@ -60,61 +50,58 @@ std::string toCheckedFmtStr(const S & format, const Ignored &, Args &&... args)
}
} // namespace LogFmtDetails

/// Logs a message to a specified logger with that level.

#define LOG_IMPL(logger, PRIORITY, message) \
do \
{ \
if ((logger)->is((PRIORITY))) \
{ \
Poco::Message poco_message( \
/*source*/ (logger)->name(), \
/*text*/ message, \
/*prio*/ (PRIORITY), \
/*file*/ &__FILE__[LogFmtDetails::getFileNameOffset(__FILE__)], \
/*line*/ __LINE__); \
(logger)->log(poco_message); \
} \
} while (false)

#define LOG_TRACE(logger, message) LOG_IMPL(logger, Poco::Message::PRIO_TRACE, message)
#define LOG_DEBUG(logger, message) LOG_IMPL(logger, Poco::Message::PRIO_DEBUG, message)
#define LOG_INFO(logger, message) LOG_IMPL(logger, Poco::Message::PRIO_INFORMATION, message)
#define LOG_WARNING(logger, message) LOG_IMPL(logger, Poco::Message::PRIO_WARNING, message)
#define LOG_ERROR(logger, message) LOG_IMPL(logger, Poco::Message::PRIO_ERROR, message)
#define LOG_FATAL(logger, message) LOG_IMPL(logger, Poco::Message::PRIO_FATAL, message)


/// Logs a message to a specified logger with that level.
/// If more than one argument is provided,
/// the first argument is interpreted as template with {}-substitutions
/// and the latter arguments treat as values to substitute.
/// If only one argument is provided, it is threat as message without substitutions.

#define LOG_GET_FIRST_ARG(arg, ...) arg
#define LOG_FMT_IMPL(logger, PRIORITY, ...) \
do \
{ \
if ((logger)->is((PRIORITY))) \
{ \
std::string formatted_message = LogFmtDetails::numArgs(__VA_ARGS__) > 1 \
? LogFmtDetails::toCheckedFmtStr( \
FMT_STRING(LOG_GET_FIRST_ARG(__VA_ARGS__)), \
__VA_ARGS__) \
: LogFmtDetails::firstArg(__VA_ARGS__); \
Poco::Message poco_message( \
/*source*/ (logger)->name(), \
/*text*/ formatted_message, \
/*prio*/ (PRIORITY), \
/*file*/ &__FILE__[LogFmtDetails::getFileNameOffset(__FILE__)], \
/*line*/ __LINE__); \
(logger)->log(poco_message); \
} \
#define LOG_INTERNAL(logger, PRIORITY, message) \
do \
{ \
Poco::Message poco_message( \
/*source*/ (logger)->name(), \
/*text*/ (message), \
/*prio*/ (PRIORITY), \
/*file*/ &__FILE__[LogFmtDetails::getFileNameOffset(__FILE__)], \
/*line*/ __LINE__); \
(logger)->log(poco_message); \
} while (false)

#define LOG_FMT_TRACE(logger, ...) LOG_FMT_IMPL(logger, Poco::Message::PRIO_TRACE, __VA_ARGS__)
#define LOG_FMT_DEBUG(logger, ...) LOG_FMT_IMPL(logger, Poco::Message::PRIO_DEBUG, __VA_ARGS__)
#define LOG_FMT_INFO(logger, ...) LOG_FMT_IMPL(logger, Poco::Message::PRIO_INFORMATION, __VA_ARGS__)
#define LOG_FMT_WARNING(logger, ...) LOG_FMT_IMPL(logger, Poco::Message::PRIO_WARNING, __VA_ARGS__)
#define LOG_FMT_ERROR(logger, ...) LOG_FMT_IMPL(logger, Poco::Message::PRIO_ERROR, __VA_ARGS__)
#define LOG_FMT_FATAL(logger, ...) LOG_FMT_IMPL(logger, Poco::Message::PRIO_FATAL, __VA_ARGS__)

#define LOG_IMPL_0(logger, PRIORITY, message) \
do \
{ \
if ((logger)->is((PRIORITY))) \
LOG_INTERNAL(logger, PRIORITY, message); \
} while (false)

#define LOG_IMPL_1(logger, PRIORITY, fmt_str, ...) \
do \
{ \
if ((logger)->is((PRIORITY))) \
{ \
auto _message = LogFmtDetails::toCheckedFmtStr(FMT_STRING(fmt_str), __VA_ARGS__); \
LOG_INTERNAL(logger, PRIORITY, _message); \
} \
} while (false)

#define LOG_IMPL_CHOSER(...) TF_GET_29TH_ARG(__VA_ARGS__, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_1, LOG_IMPL_0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you tell me why have 29 args?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because in our repo the maximum of arguments count is 26.


// clang-format off
#define LOG_IMPL(logger, PRIORITY, ...) LOG_IMPL_CHOSER(__VA_ARGS__)(logger, PRIORITY, __VA_ARGS__)
// clang-format on

#define LOG_TRACE(logger, ...) LOG_IMPL(logger, Poco::Message::PRIO_TRACE, __VA_ARGS__)
Copy link
Member

@breezewish breezewish Sep 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the doc:

A Message can also contain any number of named parameters that contain additional information about the event that caused the message.

Seems that we can even consider supporting named arguments (instead of fmt differently) in future?

cc @JaySon-Huang

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does "named arguments" means a behavior like this?

int val = 12345;
LOG_DEBUG(log, "log some value"; val);
// generate a log "log some value [val=12345]"

As Poco::Message copy the key, value to a map<string, string> then put it into the format buffer. I'm wondering whether it will bring performance regression for logging. 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spdlog may be a good alternative considering performance. It also has many convenient features.

#define LOG_DEBUG(logger, ...) LOG_IMPL(logger, Poco::Message::PRIO_DEBUG, __VA_ARGS__)
#define LOG_INFO(logger, ...) LOG_IMPL(logger, Poco::Message::PRIO_INFORMATION, __VA_ARGS__)
#define LOG_WARNING(logger, ...) LOG_IMPL(logger, Poco::Message::PRIO_WARNING, __VA_ARGS__)
#define LOG_ERROR(logger, ...) LOG_IMPL(logger, Poco::Message::PRIO_ERROR, __VA_ARGS__)
#define LOG_FATAL(logger, ...) LOG_IMPL(logger, Poco::Message::PRIO_FATAL, __VA_ARGS__)

#define LOG_FMT_TRACE(...) LOG_TRACE(__VA_ARGS__)
#define LOG_FMT_DEBUG(...) LOG_DEBUG(__VA_ARGS__)
#define LOG_FMT_INFO(...) LOG_INFO(__VA_ARGS__)
#define LOG_FMT_WARNING(...) LOG_WARNING(__VA_ARGS__)
#define LOG_FMT_ERROR(...) LOG_ERROR(__VA_ARGS__)
#define LOG_FMT_FATAL(...) LOG_FATAL(__VA_ARGS__)