Modified: trunk/Source/WebCore/PAL/pal/Logger.h (221387 => 221388)
--- trunk/Source/WebCore/PAL/pal/Logger.h 2017-08-30 18:48:35 UTC (rev 221387)
+++ trunk/Source/WebCore/PAL/pal/Logger.h 2017-08-30 19:06:49 UTC (rev 221388)
@@ -37,10 +37,12 @@
template<typename T>
struct LogArgument {
+ template<typename U = T> static typename std::enable_if<std::is_same<U, bool>::value, String>::type toString(bool argument) { return argument ? ASCIILiteral("true") : ASCIILiteral("false"); }
template<typename U = T> static typename std::enable_if<std::is_same<U, int>::value, String>::type toString(int argument) { return String::number(argument); }
template<typename U = T> static typename std::enable_if<std::is_same<U, float>::value, String>::type toString(float argument) { return String::number(argument); }
template<typename U = T> static typename std::enable_if<std::is_same<U, double>::value, String>::type toString(double argument) { return String::number(argument); }
- template<typename U = T> static typename std::enable_if<std::is_same<U, String>::value, String>::type toString(String argument) { return argument; }
+ template<typename U = T> static typename std::enable_if<std::is_same<typename std::remove_reference<U>::type, AtomicString>::value, String>::type toString(AtomicString argument) { return argument.string(); }
+ template<typename U = T> static typename std::enable_if<std::is_same<typename std::remove_reference<U>::type, String>::value, String>::type toString(String argument) { return argument; }
template<typename U = T> static typename std::enable_if<std::is_same<U, const char*>::value, String>::type toString(const char* argument) { return String(argument); }
template<size_t length> static String toString(const char (&argument)[length]) { return String(argument); }
};
@@ -48,6 +50,13 @@
class Logger : public RefCounted<Logger> {
WTF_MAKE_NONCOPYABLE(Logger);
public:
+
+ class Observer {
+ public:
+ virtual ~Observer() { }
+ virtual void didLogMessage(const WTFLogChannel&, const String&) = 0;
+ };
+
static Ref<Logger> create(const void* owner)
{
return adoptRef(*new Logger(owner));
@@ -54,7 +63,7 @@
}
template<typename... Arguments>
- inline void logAlways(WTFLogChannel& channel, const Arguments&... arguments)
+ inline void logAlways(WTFLogChannel& channel, const Arguments&... arguments) const
{
#if RELEASE_LOG_DISABLED
// "Standard" WebCore logging goes to stderr, which is captured in layout test output and can generally be a problem
@@ -69,7 +78,7 @@
}
template<typename... Arguments>
- inline void error(WTFLogChannel& channel, const Arguments&... arguments)
+ inline void error(WTFLogChannel& channel, const Arguments&... arguments) const
{
if (!willLog(channel, WTFLogLevelError))
return;
@@ -78,7 +87,7 @@
}
template<typename... Arguments>
- inline void warning(WTFLogChannel& channel, const Arguments&... arguments)
+ inline void warning(WTFLogChannel& channel, const Arguments&... arguments) const
{
if (!willLog(channel, WTFLogLevelWarning))
return;
@@ -87,7 +96,7 @@
}
template<typename... Arguments>
- inline void notice(WTFLogChannel& channel, const Arguments&... arguments)
+ inline void notice(WTFLogChannel& channel, const Arguments&... arguments) const
{
if (!willLog(channel, WTFLogLevelNotice))
return;
@@ -96,7 +105,7 @@
}
template<typename... Arguments>
- inline void info(WTFLogChannel& channel, const Arguments&... arguments)
+ inline void info(WTFLogChannel& channel, const Arguments&... arguments) const
{
if (!willLog(channel, WTFLogLevelInfo))
return;
@@ -105,7 +114,7 @@
}
template<typename... Arguments>
- inline void debug(WTFLogChannel& channel, const Arguments&... arguments)
+ inline void debug(WTFLogChannel& channel, const Arguments&... arguments) const
{
if (!willLog(channel, WTFLogLevelDebug))
return;
@@ -113,7 +122,7 @@
log(channel, arguments...);
}
- inline bool willLog(WTFLogChannel& channel, WTFLogLevel level) const
+ inline bool willLog(const WTFLogChannel& channel, WTFLogLevel level) const
{
if (level != WTFLogLevelAlways && level > channel.level)
return false;
@@ -133,40 +142,95 @@
}
struct MethodAndPointer {
- MethodAndPointer(const char* methodName, void* objectPtr)
- : methodName(methodName)
- , objectPtr(reinterpret_cast<uintptr_t>(objectPtr))
+ MethodAndPointer(const char* methodName, const void* objectPtr)
+ : methodName { methodName }
+ , objectPtr { reinterpret_cast<uintptr_t>(objectPtr) }
{
}
- const char* methodName;
- uintptr_t objectPtr;
+ MethodAndPointer(const char* className, const char* methodName, const void* objectPtr)
+ : className { className }
+ , methodName { methodName }
+ , objectPtr { reinterpret_cast<uintptr_t>(objectPtr) }
+ {
+ }
+
+ const char* className { nullptr };
+ const char* methodName { nullptr };
+ const uintptr_t objectPtr { 0 };
};
+ static inline void addObserver(Observer& observer)
+ {
+ observers().append(observer);
+ }
+ static inline void removeObserver(Observer& observer)
+ {
+ observers().removeFirstMatching([&observer](auto anObserver) {
+ return &anObserver.get() == &observer;
+ });
+ }
+
private:
- Logger(const void* owner) { m_owner = owner; }
+ Logger(const void* owner)
+ : m_owner { owner }
+ {
+ }
template<typename... Argument>
static inline void log(WTFLogChannel& channel, const Argument&... arguments)
{
- String string = makeString(LogArgument<Argument>::toString(arguments)...);
+ String logMessage = makeString(LogArgument<Argument>::toString(arguments)...);
#if RELEASE_LOG_DISABLED
- WTFLog(&channel, "%s", string.utf8().data());
+ WTFLog(&channel, "%s", logMessage.utf8().data());
#else
- os_log(channel.osLogChannel, "%{public}s", string.utf8().data());
+ os_log(channel.osLogChannel, "%{public}s", logMessage.utf8().data());
#endif
+
+ for (Observer& observer : observers())
+ observer.didLogMessage(channel, logMessage);
}
+ static Vector<std::reference_wrapper<Observer>>& observers()
+ {
+ static NeverDestroyed<Vector<std::reference_wrapper<Observer>>> observers;
+ return observers;
+ }
+
const void* m_owner;
bool m_enabled { true };
};
+class LogHelper {
+public:
+ virtual ~LogHelper() = default;
+
+ virtual const Logger& logger() const = 0;
+ virtual const char* className() const = 0;
+ virtual WTFLogChannel& logChannel() const = 0;
+
+ inline bool willLog(WTFLogLevel level) const { return logger().willLog(logChannel(), level); }
+
+#define ALWAYS_LOG(...) logger().logAlways(logChannel(), Logger::MethodAndPointer(className(), __func__, this), ##__VA_ARGS__)
+#define ERROR_LOG(...) logger().error(logChannel(), Logger::MethodAndPointer(className(), __func__, this), ##__VA_ARGS__)
+#define WARNING_LOG(...) logger().warning(logChannel(), Logger::MethodAndPointer(className(), __func__, this), ##__VA_ARGS__)
+#define NOTICE_LOG(...) logger().notice(logChannel(), Logger::MethodAndPointer(className(), __func__, this), ##__VA_ARGS__)
+#define INFO_LOG(...) logger().info(logChannel(), Logger::MethodAndPointer(className(), __func__, this), ##__VA_ARGS__)
+#define DEBUG_LOG(...) logger().debug(logChannel(), Logger::MethodAndPointer(className(), __func__, this), ##__VA_ARGS__)
+
+};
+
template <>
struct LogArgument<Logger::MethodAndPointer> {
static String toString(const Logger::MethodAndPointer& value)
{
StringBuilder builder;
+
+ if (value.className) {
+ builder.append(value.className);
+ builder.appendLiteral("::");
+ }
builder.append(value.methodName);
builder.appendLiteral("(0x");
appendUnsigned64AsHex(value.objectPtr, builder);
@@ -176,4 +240,3 @@
};
} // namespace PAL
-
Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/Logging.cpp (221387 => 221388)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/Logging.cpp 2017-08-30 18:48:35 UTC (rev 221387)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/Logging.cpp 2017-08-30 19:06:49 UTC (rev 221388)
@@ -55,8 +55,13 @@
namespace TestWebKitAPI {
-class LoggingTest : public testing::Test {
+class LoggingTest : public testing::Test, public LogHelper {
public:
+ LoggingTest()
+ : m_logger { Logger::create(this) }
+ {
+ }
+
void SetUp() final
{
WTF::initializeMainThread();
@@ -94,7 +99,13 @@
return result.toString();
}
+ const Logger& logger() const final { return m_logger.get(); }
+ const char* className() const final { return "LoggingTest"; }
+ WTFLogChannel& logChannel() const final { return TestChannel1; }
+
private:
+
+ Ref<Logger> m_logger;
int m_descriptors[2];
FILE* m_stderr;
};
@@ -267,6 +278,7 @@
EXPECT_TRUE(logger->enabled());
WTFSetLogChannelLevel(&TestChannel1, WTFLogLevelError);
+ EXPECT_TRUE(logger->willLog(TestChannel1, WTFLogLevelError));
logger->error(TestChannel1, "You're using coconuts!");
EXPECT_TRUE(output().contains("You're using coconuts!", false));
logger->warning(TestChannel1, "You're using coconuts!");
@@ -302,10 +314,107 @@
EXPECT_TRUE(output().contains("I shall taunt you a second time!", false));
logger->setEnabled(this, false);
+ EXPECT_FALSE(logger->willLog(TestChannel1, WTFLogLevelError));
+ EXPECT_FALSE(logger->willLog(TestChannel1, WTFLogLevelWarning));
+ EXPECT_FALSE(logger->willLog(TestChannel1, WTFLogLevelNotice));
+ EXPECT_FALSE(logger->willLog(TestChannel1, WTFLogLevelInfo));
+ EXPECT_FALSE(logger->willLog(TestChannel1, WTFLogLevelDebug));
EXPECT_FALSE(logger->enabled());
logger->logAlways(TestChannel1, "You've got two empty halves of coconuts");
EXPECT_EQ(0u, output().length());
+
+ logger->setEnabled(this, true);
+ AtomicString string1("AtomicString", AtomicString::ConstructFromLiteral);
+ const AtomicString string2("const AtomicString", AtomicString::ConstructFromLiteral);
+ logger->logAlways(TestChannel1, string1, " and ", string2);
+ EXPECT_TRUE(output().contains("AtomicString and const AtomicString", false));
+
+ String string3("String");
+ const String string4("const String");
+ logger->logAlways(TestChannel1, string3, " and ", string4);
+ EXPECT_TRUE(output().contains("String and const String", false));
}
+
+TEST_F(LoggingTest, LogHelper)
+{
+ EXPECT_TRUE(logger().enabled());
+
+ StringBuilder builder;
+ builder.appendLiteral("LoggingTest::TestBody(0x");
+ appendUnsigned64AsHex(reinterpret_cast<uintptr_t>(this), builder);
+ builder.appendLiteral(")");
+ String signature = builder.toString();
+
+ ALWAYS_LOG();
+ EXPECT_TRUE(this->output().contains(signature, false));
+
+ ALWAYS_LOG("Welcome back", " my friends", " to the show", " that never ends");
+ String result = this->output();
+ EXPECT_TRUE(result.contains(signature, false));
+ EXPECT_TRUE(result.contains("to the show that never", false));
+
+ WTFSetLogChannelLevel(&TestChannel1, WTFLogLevelWarning);
+ EXPECT_TRUE(willLog(WTFLogLevelWarning));
+
+ ERROR_LOG("We're so glad you could attend");
+ EXPECT_TRUE(output().contains("We're so glad you could attend", false));
+
+ WARNING_LOG("Come inside! ", "Come inside!");
+ EXPECT_TRUE(output().contains("Come inside! Come inside!", false));
+
+ NOTICE_LOG("There behind a glass is a real blade of grass");
+ EXPECT_EQ(0u, output().length());
+
+ INFO_LOG("be careful as you pass.");
+ EXPECT_EQ(0u, output().length());
+
+ DEBUG_LOG("Move along! Move along!");
+ EXPECT_EQ(0u, output().length());
+}
+
+class LogObserver : public Logger::Observer {
+public:
+ LogObserver() = default;
+
+ String log()
+ {
+ String log = m_logBuffer.toString();
+ m_logBuffer.clear();
+
+ return log;
+ }
+
+ WTFLogChannel channel() const { return m_lastChannel; }
+
+private:
+ void didLogMessage(const WTFLogChannel& channel, const String& logMessage) final
+ {
+ m_logBuffer.append(logMessage);
+ m_lastChannel = channel;
+ }
+
+ StringBuilder m_logBuffer;
+ WTFLogChannel m_lastChannel;
+};
+
+TEST_F(LoggingTest, LogObserver)
+{
+ LogObserver observer;
+
+ EXPECT_TRUE(logger().enabled());
+
+ logger().addObserver(observer);
+ ALWAYS_LOG("testing 1, 2, 3");
+ EXPECT_TRUE(this->output().contains("testing 1, 2, 3", false));
+ EXPECT_TRUE(observer.log().contains("testing 1, 2, 3", false));
+ EXPECT_STREQ(observer.channel().name, logChannel().name);
+
+ logger().removeObserver(observer);
+ ALWAYS_LOG("testing ", 1, ", ", 2, ", 3");
+ EXPECT_TRUE(this->output().contains("testing 1, 2, 3", false));
+ EXPECT_EQ(0u, observer.log().length());
+}
+
#endif
} // namespace TestWebKitAPI