Commit 134472ee authored by Phil Willoughby's avatar Phil Willoughby Committed by Facebook Github Bot

add glog->folly log bridge

Summary: This class is intended to be useful when part of your project is using folly logging and part is using glog - simply install this bridge up-front and everything is routed to folly logging.

Reviewed By: simpkins

Differential Revision: D19952822

fbshipit-source-id: 898846fc7b647ddd93222f46c56450c1454dc738
parent 8fd9c637
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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.
*/
#include <folly/logging/BridgeFromGoogleLogging.h>
#include <folly/logging/Logger.h>
#include <folly/logging/xlog.h>
namespace folly {
namespace logging {
namespace {
constexpr folly::LogLevel asFollyLogLevel(::google::LogSeverity severity) {
switch (severity) {
case ::google::GLOG_FATAL:
return folly::LogLevel::FATAL;
case ::google::GLOG_ERROR:
return folly::LogLevel::ERR;
case ::google::GLOG_WARNING:
return folly::LogLevel::WARNING;
case ::google::GLOG_INFO:
return folly::LogLevel::INFO;
default:
return folly::LogLevel::INFO2;
}
}
} // namespace
BridgeFromGoogleLogging::BridgeFromGoogleLogging() {
::google::AddLogSink(this);
}
BridgeFromGoogleLogging::~BridgeFromGoogleLogging() noexcept {
::google::RemoveLogSink(this);
}
void BridgeFromGoogleLogging::send(
::google::LogSeverity severity,
const char* full_filename,
const char* base_filename,
int line,
const struct ::tm* pTime,
const char* message,
size_t message_len,
::gflags::int32 usecs) {
struct ::tm time = *pTime;
folly::Logger const logger{full_filename};
auto follyLevel = asFollyLogLevel(severity);
if (logger.getCategory()->logCheck(follyLevel)) {
folly::LogMessage logMessage{
logger.getCategory(),
follyLevel,
std::chrono::system_clock::from_time_t(mktime(&time)) +
std::chrono::microseconds(usecs),
base_filename,
static_cast<unsigned>(line),
{},
std::string{message, message_len}};
logger.getCategory()->admitMessage(logMessage);
}
}
void BridgeFromGoogleLogging::send(
::google::LogSeverity severity,
const char* full_filename,
const char* base_filename,
int line,
const struct ::tm* pTime,
const char* message,
size_t message_len) {
struct ::tm time = *pTime;
auto usecs = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::system_clock::now() -
std::chrono::system_clock::from_time_t(mktime(&time)));
send(
severity,
full_filename,
base_filename,
line,
pTime,
message,
message_len,
usecs.count());
}
} // namespace logging
} // namespace folly
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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 GLOG_NO_ABBREVIATED_SEVERITIES
#include <glog/logging.h>
namespace folly {
namespace logging {
/* Class to bridge GLOG to folly logging.
*
* You only need one instance of this class in your program at a time. While
* it's in scope it will bridge all GLOG messages to the folly logging
* pipeline.
*
* You probably want this very early in `main` as:
* folly::logging::BridgeFromGoogleLogging glogToXlogBridge{};
*/
struct BridgeFromGoogleLogging : ::google::LogSink {
BridgeFromGoogleLogging();
~BridgeFromGoogleLogging() noexcept override;
void send(
::google::LogSeverity severity,
const char* full_filename,
const char* base_filename,
int line,
const struct ::tm* pTime,
const char* message,
size_t message_len,
::google::int32 usecs);
void send(
::google::LogSeverity severity,
const char* full_filename,
const char* base_filename,
int line,
const struct ::tm* pTime,
const char* message,
size_t message_len) override;
};
} // namespace logging
} // namespace folly
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* 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.
*/
#include <folly/logging/xlog.h>
#include <folly/logging/BridgeFromGoogleLogging.h>
#include <folly/logging/LogConfigParser.h>
#include <folly/logging/LogHandler.h>
#include <folly/logging/LogMessage.h>
#include <folly/logging/LoggerDB.h>
#include <folly/logging/test/TestLogHandler.h>
#include <folly/portability/GTest.h>
#include <folly/test/TestUtils.h>
using namespace folly;
using std::make_shared;
namespace {
class BridgeFromGoogleLoggingTest : public testing::Test {
public:
BridgeFromGoogleLoggingTest() {
// Note that the XLOG* macros always use the main LoggerDB singleton.
// There is no way to get them to use a test LoggerDB during unit tests.
//
// In order to ensure that changes to the LoggerDB singleton do not persist
// across test functions we reset the configuration to a fixed state before
// each test starts.
auto config =
parseLogConfig(".=WARN:default; default=stream:stream=stderr");
LoggerDB::get().resetConfig(config);
}
};
} // namespace
TEST_F(BridgeFromGoogleLoggingTest, bridge) {
auto handler = make_shared<TestLogHandler>();
logging::BridgeFromGoogleLogging test_bridge{};
LoggerDB::get().getCategory("")->addHandler(handler);
auto& messages = handler->getMessages();
// info messages are not enabled initially.
EXPECT_FALSE(XLOG_IS_ON(INFO));
EXPECT_TRUE(XLOG_IS_ON(ERR));
LOG(INFO) << "testing 1";
EXPECT_EQ(0, messages.size());
messages.clear();
// Increase the log level, then log a message.
LoggerDB::get().setLevel("", LogLevel::INFO);
LOG(INFO) << "testing: " << 1 << 2 << 3;
ASSERT_EQ(1, messages.size());
EXPECT_EQ("testing: 123", messages[0].first.getMessage());
EXPECT_TRUE(messages[0].first.getFileName().endsWith(
"BridgeFromGoogleLoggingTest.cpp"))
<< "unexpected file name: " << messages[0].first.getFileName();
EXPECT_EQ(LogLevel::INFO, messages[0].first.getLevel());
messages.clear();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment